Saya pikir ergonomi generator tumbuh dalam diri saya.

 – Beragampengetahuan
14 mins read

Saya pikir ergonomi generator tumbuh dalam diri saya. – Beragampengetahuan

Saya mencoba untuk lebih akrab dengan iterator, iterasi dan generator. Saya pikir saya mulai menyukai ergonomi.

Saya suka javascript “gula sintetis” yang telah saya lihat selama dekade terakhir (fitur panah, teks templat, alokasi destruktif, dll.). Saya pikir ini karena sebagian besar fitur ini memecahkan poin rasa sakit nyata bagi saya (saya bahkan tidak tahu saya punya). Manfaatnya jelas, dan ada banyak peluang untuk melambaikannya.

Tetapi ada beberapa angka ganjil di luar sana, seperti fungsi generator. Mereka ada selama fitur ES2015+ kunci lainnya, tetapi kepraktisannya tidak sepenuhnya menarik. Anda bahkan mungkin tidak mengenalinya segera:

function* generateAlphabet() {
  yield "a";
  yield "b";
  
  yield "z";
}

Agar adil, saya memiliki Temukan mereka yang nyaman setidaknya sekali. Saya telah menulis tentang menggunakannya untuk mematahkan sejumlah tuntutan. Saya masih suka kasus penggunaan semacam itu, tetapi saya bertanya -tanya apakah saya kehilangan sesuatu.

Jadi, saya ingin memberi mereka goyangan yang jujur ​​dan disengaja. Mungkin setelah Anda merasa lebih baik tentang mereka, kemungkinan akan muncul. Yang mengejutkan saya, saya pikir setidaknya dalam beberapa kasus, saya mulai menghargai model mental yang ergonomis dan mendorong yang mereka tawarkan. Saya akan mencoba mengungkap di mana saya. Pertama, mari kita mundur selangkah dan memperkaya segalanya.

Kecuali kita menutupi dua protokol berbeda yang mereka andalkan, generator tidak akan masuk akal: Iterator Dan merasa protokol. Mereka berdua menghadapinya Proses menghasilkan urutan nilai yang tidak pasti. Perjanjian terakhir didasarkan pada yang pertama.

Contents

Protokol Iterator

Ini menstandarkan bentuk dan perilaku objek yang mengembalikan urutan. Setidaknya, objek apa pun adalah iterator jika situasi berikut adalah:

  • Itu terbuka a next() Metode yang mengembalikan objek dengan dua atribut:

Itu saja. Ini bagus dan sederhana:

const gospelIterator = {
  index: -1,

  next() {
    const gospels = ["Matthew", "Mark", "Luke", "John"];
    this.index++;

    return {
      value: gospels.at(this.index),
      done: this.index + 1 > gospels.length,
    };
  },
};

gospelIterator.next(); 
gospelIterator.next(); 
gospelIterator.next(); 
gospelIterator.next(); 
gospelIterator.next(); 

Tidak ada urutan memiliki Omong-omong. Iterator yang tak terbatas sangat baik -baik saja:

const infiniteIterator = {
  count: 0,
  next() {
    this.count++;

    return {
      value: this.count,
      done: false,
    };
  },
};

infiniteGenerator.next(); 

Selain memberikan beberapa konsistensi, protokol ini sendiri mungkin tidak terlalu berguna. ini Protokol berulang Itu harus membantu.

Protokol yang dapat diulang

Objek adalah merasa Jika ada satu [Symbol.iterator]() Metode pengembalian Iterator Tujuan. Setiap kali Anda menggunakan for...of Loop atau hancurkan array, Anda telah memanfaatkan protokol ini. Itu dibangun secara umum, termasuk String,,,,, ArrayDan Map.

Menerapkannya sendiri memungkinkan Anda untuk menentukan caranya for...of Perilaku melingkar. Bangun contoh dari atas, ini adalah objek yang dapat dikonfigurasi:

const gospelIteratable = {
  [Symbol.iterator]() {
    return {
      index: -1,

      next() {
        const gospels = ["Matthew", "Mark", "Luke", "John"];
        this.index++;

        return {
          value: gospels.at(this.index),
          done: this.index + 1 > gospels.length,
        };
      },
    };
  },
};

Sekarang, dua for...of Looping dan destruktif hanya akan berhasil:

for (const author of gospelIteratable) {
  console.log(author); 
}

console.log([...gospelIteratable]);

Mari lulus dengan contoh yang tidak mudah untuk meniru array sederhana. Ini diulangi di setiap tahun lompatan setelah 1900:

function isLeapYear(year) {
  return year % 100 === 0 ? year % 400 === 0 : year % 4 === 0;
}

const leapYears = {
  [Symbol.iterator]() {
    return {
      startYear: 1900,
      currentYear: new Date().getFullYear(),
      next() {
        this.startYear++;

        while (!isLeapYear(this.startYear)) {
          this.startYear++;
        }

        return {
          value: this.startYear,
          done: this.startYear > this.currentYear,
        };
      },
    };
  },
};

for (const leapYear of leapYears) {
  console.log(leapYear);
}

Harap dicatat bahwa kami tidak perlu menunggu Seluruh urutan Beberapa tahun untuk segera dibangun. Semua negara disimpan dalam objek berulang itu sendiri, dan item berikutnya dihitung sesuai permintaan. Perlu disebutkan.

Penilaian malas

Evaluasi malas adalah salah satu manfaat terbesar dari tingkat iterasi. Kami tidak membutuhkan Setiap item dalam urutan dapat dimulai. Dalam beberapa kasus, ini bisa menjadi cara yang baik untuk mencegah masalah kinerja.

Temui kami leapYears Merasa lagi. Jika Anda ingin tetap bertahan for Mengulangi nilai -nilai ini, tapi TIDAK Menggunakan yang penting, Anda mungkin telah mencapai array prefabrikasi:

const leapYears = [];
const startYear = 1900;
const currentYear = new Date().getFullYear();

for (let year = startYear + 1; year <= currentYear; year++) {
  if (isLeapYear(year)) {
      leapYears.push(year);
    }
}

for (const leapYear of leapYears) {
  console.log(leapYear);
}

Kode ini tentu saja jelas dan dapat dibaca (banyak yang akan mengatakan lebih dari versi sebelumnya), tetapi ada trade-off: kami mengeksekusi dua for Loop daripada satu, yang lebih penting, menghadapinya Seluruh daftar nilai. Untuk skema seperti itu, ini adalah dampak yang dapat diabaikan, tetapi perpajakan dapat ditingkatkan untuk perhitungan yang mahal atau set data yang lebih besar. Memikirkan sesuatu seperti ini:

for (const thing of getExpensiveThings(1000)) {
  
}

Tidak ada pertanyaan khusus getExpensiveThings()seluruh daftar 1.000 proyek harus dibangun Sebelum apapun Dapat dilakukan dalam satu lingkaran. Waktu antara mengeksekusi skrip dan melakukan hal -hal berharga tidak perlu.

Sekali lagi, ini bagus saat Anda tidak membutuhkan Setiap item dalam urutan. Mungkin Anda ingin menemukan tahun pertama yang dialami seseorang sebelum tahun kelahiran. Setelah dikonfirmasi, tidak ada alasan untuk melanjutkan. Jika array prefabrikasi digunakan, beberapa di antaranya pada akhirnya akan diisi tanpa apa -apa.

function getFirstLeapYear(birthYear) {
  for (const leapYear of leapYears) {
    if (leapYear >= birthYear) return leapYear;
  }
  
  return null;
}


getFirstLeapYear(1989) 

Jelas, dengan pekerjaan yang sangat padat sumber daya, keuntungan efisiensi akan lebih menyenangkan, tetapi Anda mendapatkannya. Jika tidak ada proyek yang dibutuhkan, tidak ada perhitungan yang terbuang untuk mempersiapkannya.

Jika Anda marah tentang bagaimana perasaan Anda tentang membangun salah satunya, Anda akhirnya melompat ke generator, fitur build, yang membuat semuanya lebih ergonomis, maka Anda dalam kondisi yang baik.

Ini dimulai dari atas, tetapi ditulis sebagai Fungsi generator, kembali Generator 0bject.

function* generateGospels() {
  yield "Matthew";
  yield "Mark";
  yield "Luke";
  yield "John";
}

Berikut adalah dua struktur penting: function* Dan yield Kata kunci. Yang pertama menandai itu sebagai fungsi generator, Anda dapat memikirkannya yield Setiap kali generator diminta untuk memberikan nilai berikutnya, kata kunci digunakan sebagai klik “jeda”.

Di bawah kap, hal yang sama next() Metode ini juga disebut. Setiap kali dipanggil, itu akan pindah ke yang berikutnya yield Pernyataan (kecuali tidak ada lagi).

const generator = generateGospels();

console.log(generator.next()); 

Tentu saja, milik kami for...of Loop berperilaku seperti yang diharapkan:

for (const gospel of generateGospels()) {
  console.log(gospel);
}




Ingat: iterasi (dan generator) bisa tak terbatasyang berarti Anda mungkin melihat sesuatu yang serupa di alam liar:

function* multipleGenerator(base) {
  let current = base;

  while (true) {
    yield current;

    current += base;
  }
}

Loop seperti ini terlihat mengerikan, tetapi mereka tidak harus mengunci browser Anda. Hanya satu yield Di antara setiap iterasi, semuanya berhenti ketika nilai berikutnya diminta, dan eksekusi dapat dilakukan dengan cara yang bahagia.

const multiplier = multipleGenerator(22);

multiplier.next(); 
multiplier.next(); 
multiplier.next(); 

Yaitu sesuatu yang layak dilihat: eksekusi generator sinkronisjadi masih ada banyak peluang untuk mendukung utas utama. Untungnya, ada beberapa cara untuk mencegahnya. Ada yang lain AsyncGenerator dapat membantu objek yang mengarah pada tantangan seperti itu.

Tidak ada kemampuan inovatif di sini. Saya kesulitan menemukan masalah yang tidak dapat diselesaikan dengan metode yang lebih umum. Tetapi ketika saya mulai bekerja dengan mereka lebih banyak, saya akan lebih menghargai generator. Beberapa alasan untuk berpikir:

Mereka dapat membantu mengurangi kopling ketat.

Generator (dan semua iterator lainnya) bersinar untuk merangkum diri mereka sendiri, termasuk manajemen negara mereka sendiri. Semakin banyak, saya perhatikan bagaimana ini membantu meringankan kopling antara komponen yang telah saya saling bergantung secara membabi buta.

Skema: Saat mengklik tombol, Anda ingin mulai menampilkan beberapa rata -rata harga selama lima tahun terakhir sejak lama. Anda hanya perlu rata -rata rata -rata jendela, dan mungkin bahkan tidak semua item yang mungkin dalam koleksi (pengguna tidak boleh mengklik sepanjang waktu). Ini akan melakukan pekerjaan:

let windowStart = 0;

function calculateMovingAverage(values, windowSize) {
  const section = values.slice(windowStart, windowStart + windowSize);

  if (section.length < windowSize) return null;

  return section.reduce((sum, val) => sum + val, 0) / windowSize;
}

loadButton.addEventListener("click", function () {
  const avg = calculateMovingAverage(prices, 5);
  average.innerHTML = `Average: $${avg}`;
  windowStart++;
});

Setiap kali tombol diklik, rata -rata berikutnya disajikan ke layar. Tapi ini timpang, kita harus bertahan windowStart Pada berbagai variabel yang tinggi, saya tidak merasa senang memiliki pendengar aktivitas yang bertanggung jawab untuk memperbarui status itu. Saya ingin fokus pada memperbarui UI.

Yang paling penting, saya mungkin juga ingin mendapatkan nilai rata -rata di tempat lain di halaman. Sulit untuk bersinggungan dengan yang lainnya. Batasnya lemah dan portabilitas tidak mengemudi.

Generator akan membantu menyelesaikan masalah ini:

function* calculateMovingAverage(values, windowSize) {
  let windowStart = 0;

  while (windowStart <= values.length - 1) {
    const section = values.slice(windowStart, windowStart + windowSize);
    
    yield section.reduce((sum, val) => sum + val, 0) / windowSize;
    
    windowStart++;
  }
}

const generator = calculateMovingAverage(prices, 5);

loadButton.addEventListener("click", function () {
  const { value } = generator.next();
  average.innerHTML = `Average: $${value}`;
});

Ada beberapa hak istimewa yang bagus:

  • ini windowStart Variabel hanya diekspos di tempat yang dibutuhkan. TIDAK.
  • Karena negara dan logika independen, Anda dapat menggunakan beberapa generator berbeda secara paralel tanpa masalah.
  • Semuanya lebih fokus pada tujuan. Status matematika + diserahkan kepada generator dan klik pawang untuk memperbarui DOM. Batas yang jelas.

Saya suka model itu. Kita bisa mendorongnya lebih jauh. Sampai sekarang, penangan klik adalah a Memerlukan Nilai berikutnya tergantung langsung pada generator kami yang menyediakannya. Tapi kita bisa membalikkannya ke kepala, memungkinkan generator untuk memberikan nilai yang sudah siap pakai sehingga penangan klik dapat mengeksekusi hanya Ada sesuatu. Tidak perlu memahami kompleksitas satu sama lain.

for (const value of calculateMovingAverage(prices, 5)) {
  await new Promise((r) => {
    loadButton.addEventListener(
      "click",
      function () {
        average.innerHTML = `Average: $${value}`;
        r();
      },
      { once: true }
    );
  });
}

Aku bisa merasakan kepala berputar dan hidungku gemetar. Ini bukan pola yang menurut saya alami, tetapi saya menghormati fakta bahwa itu mungkin. Jika prinsip “inversi kontrol” memikirkannya, itu juga melakukannya untuk saya. Hampir tidak ada saling ketergantungan; Tidak perlu satu komponen untuk memahami detail implementasi komponen lain. Setelah pekerjaan selesai, pendengar membersihkan dan mengendalikan generator. Intuisi saya mengatakan Paman Bob setidaknya akan berterima kasih atas sentimennya (jika tidak, Tolong Biarkan saya menjadi subjek raungan jubah mandi.

Mereka dapat membantu menghindari hampir tidak ada hal yang “menjengkelkan”.

Saya terkejut dengan praktik menjengkelkan yang harus saya gunakan di masa lalu. Berpikir: Rekursi, panggilan balik, dll. Mereka tidak salah, tetapi mereka tidak menyebabkan sukacita.

Salah satu bidang persepsi adalah siklus reguler. Pikirkan menampilkan dasbor setiap detik, menampilkan aplikasi terbaru setiap detik. Fitur seperti itu dapat dibagi menjadi dua masalah: meminta data dan menerimanya ke UI. Ada banyak opsi untuk diselesaikan:

setInterval()

Anda dapat memilih klasik setInterval() – Pilihan yang tepat karena tujuan keseluruhannya adalah untuk melakukan hal -hal berulang -ulang (dan kemudian).



function monitorVitals(cb) {
  setInterval(async () => {
    const vitals = await requestVitals();

    cb(vitals);
  }, 1000);
}

monitorVitals((vitals) => {
  console.log("Update the UI...", vitals);
});

Tetapi beberapa hal mungkin mengganggu Anda. Untuk memisahkan dua masalah ini, diperlukan panggilan balik, yang dapat memicu luka yang dalam pada “neraka panggilan balik” dari hari kenabian Javascript. Yang paling penting, interval tidak peduli berapa lama untuk meminta data. bertanya Bisa Waktu akhir berlangsung lebih lama dari interval Anda, menghasilkan masalah penyortiran yang aneh.

setTimeout()

Sebagai alternatif, mungkin Anda akan memilih paket rekursif dan janji setTimeout():

async function monitorVitals(cb) {
  const vitals = await requestVitals();

  cb(vitals);

  await new Promise((r) => {
    setTimeout(() => monitorVitals(cb), 1000);
  });
}

monitorVitals((vitals) => {
  console.log("Update the UI...", vitals);
});

Itu bagus juga. Tetapi rekursi mungkin telah membunuh kakek buyut Anda dalam perang, dan Anda tidak ingin menghidupkan kembali trauma itu. Anda masih perlu lulus panggilan balik ini.

while(){}

Ada juga yang tak terbatas while Loop, didekomposisi oleh beberapa kode asinkron.

async function monitorVitals(cb) {
  while (true) {
    await new Promise((r) => setTimeout(r, 1000));

    const vitals = await requestVitals();
    cb(vitals);
  }
}

monitorVitals((vitals) => {
  console.log("Update the UI...", vitals);
});

Tidak ada lagi rekursi, tetapi panggilan balik masih ada. Sekali lagi, tidak ada masalah dalam contoh -contoh ini di alam. Ini hanya duri kecil. Untungnya, ada pilihan lain.

Input: Generator Asinkron

Saya mengisyaratkan ini sebelumnya. Generator konvensional bisa asinkron dinamo Dengan penempatan async Dalam definisinya. Tulisannya jelas, tapi itu istimewa. Generator asinkron dapat digunakan for await Loop berjalan melalui urutan nilai parsed.

async function* generateVitals() {
  while (true) {
    const result = await requestVitals();

    await new Promise((r) => setTimeout(r, 1000));

    yield result
  }
}

for await (const vitals of generateVitals()) {
  console.log("Update the UI...", vitals);
}

Perilaku yang dihasilkannya sama, tetapi tidak ada pemicu emosional. Tidak ada risiko waktu, tidak ada rekursi, dan tidak ada panggilan balik. Kekhawatiran unik dapat menjaga diri Anda dengan rapi. Yang perlu Anda lakukan adalah memproses urutan.

Jika Anda perlu membagun setiap sumber daya, Anda mungkin melakukan hal seperti ini.

async function fetchAllItems() {
  let currentPage = 1;
  let hasMore = true;
  let items = [];

  while (hasMore) {
    const data = await requestFromApi(currentPage);

    hasMore = data.hasMore;
    currentPage++;
    
    items = items.concat(data.items);
  }

  return items;
}

Beberapa orang dapat menyingkirkan perasaan kedamaian penuh dengan begitu banyak variabel tambahan dan mendaftar jahitannya. Belum lagi, Anda harus menunggu API benar -benar kelelahan maju Hal -hal yang lebih menarik mungkin terjadi.

const allItems = await fetchAllItems();


for (const item of items) {
  
}

Bukan solusi yang paling bertanggung jawab dalam hal waktu atau efisiensi memori. Saat meminta setiap halaman, kami dapat menyelesaikannya dengan refactoring proyek pemrosesan, tetapi kami dapat mengalami masalah yang sama yang telah kami jelajahi sejauh ini.

Gunakan opsi ini sebagai gantinya:

async function* fetchAllItems() {
  let currentPage = 1;

  while (true) {
    const data = await requestFromApi(currentPage);

    if (!data.hasMore) return;

    currentPage++;

    yield data.items;
  }
}

for await (const items of fetchAllItems()) {
  
}

Lebih sedikit variabel tambahan, lebih sedikit waktu sebelum pemrosesan dimulai, dan fokusnya tetap tersembunyi dengan rapi di antara satu sama lain. Bagus.

Mereka membuatnya hebat untuk menghasilkan satu set dengan cepat.

Saya menyebutkan ini sejak awal, tapi itu bagus, saya akan memuji lagi. Karena generator baik -baik saja, mereka akan dihancurkan seperti array apa pun. Jika Anda membutuhkan utilitas untuk menghasilkan berbagai batch, generator membuatnya sangat sederhana:

function* getElements(tagName = 'div') {
  while (true) yield document.createElement(tagName);
}

Sekarang, hancurkan sebanyak yang Anda bisa:

const [el1, el2, el3] = getElements('div');

Indah secara obyektif. Untuk detail lebih lanjut tentang tip ini, lihat posting lengkapnya.

Sulit untuk mengatakan apakah penemuan generator baru saya akan bertahan lama (saya mungkin masih dalam fase bulan madu dengan mereka sekarang).

Tetapi bahkan jika gairah besok berlalu, saya senang saya memiliki lebih banyak perwakilan. Adalah baik dan berharga untuk mengetahui cara menggunakan alat ini, tetapi dipaksa untuk memikirkan kembali cara saya cenderung menyelesaikan masalah bahkan lebih baik. ROI yang bagus.

rencana pengembangan website



metode pengembangan website

jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website

#Saya #pikir #ergonomi #generator #tumbuh #dalam #diri #saya

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *