Sejarah Singkat Fitur Asinkron Javascript

Ketika saya mempelajari Javascript, saya menemukan banyak artikel tentang fungsi dan operasi asinkron berulang-ulang. Terlepas dari kelebihan yang tidak diragukan dari fungsi seperti itu, setiap kali saya dituntun ke kesulitan oleh daftar yang dikutip oleh penulis. Kata-kata itu berubah, intinya tetap sama, bubur itu muncul di kepalaku. Di bawah cut - panduan kecil untuk pengembangan historis dan versi ECMA.

Mengapa kita perlu operasi asinkron?


Program komputer dapat melakukan banyak tugas tanpa batas. Bukan rahasia lagi bahwa aplikasi web harus bekerja dengan banyak tugas berbeda, yang seringkali perlu menggunakan data yang sama. Secara khusus, salah satu contoh paling umum adalah menampilkan informasi pengguna (UI) dan mengambil informasi menggunakan permintaan server. Tidak mengherankan, hampir setiap pengembang web menghadapi hal ini: bekerja dengan database yang diberikan, menyediakan antarmuka pengguna, mengatur beberapa API - semua ini secara harfiah dalam setiap tugas pengujian tidak hanya programmer JS.

Mengapa tidak menjalankan perintah secara berurutan?

Seringkali informasi yang dibutuhkan oleh pengguna dapat diperoleh hanya setelah periode waktu yang cukup lama. Jika Anda mengatur program sebagai:

  1. Mendapatkan informasi dari situs https: / some / api / item / 1
  2. Tampilkan informasi tentang item pertama di layar.

kesulitan serius akan muncul dengan merender halaman dan menciptakan kesan yang menyenangkan pada pengguna (yang disebut pengalaman pengguna). Bayangkan saja: halaman, katakanlah, Netflix atau Aliexpress harus mendapatkan data dari ratusan basis data sebelum mulai menampilkan konten kepada pengguna. Penundaan seperti itu akan mirip dengan memuat level game 3D, dan jika pemain siap menunggu, maka pengguna situs web ingin mendapatkan informasi terbanyak saat ini.

Solusinya ditemukan: operasi asinkron . Sementara utas utama dari program ini sibuk menginisialisasi dan menampilkan elemen-elemen situs web di atas kanvas, ia juga menampilkan tugas-tugas ke utas lainnya dengan semangat “ dapatkan Barang untuk Pengguna ”. Segera setelah utas ini menyelesaikan pekerjaannya, informasi "mengendap" di utas utama, dan menjadi tersedia untuk ditampilkan, dan pada halaman web itu sendiri ada placeholder tertentu - objek yang membutuhkan ruang untuk informasi masa depan.

gambar

Pada titik ini, halaman sudah ditampilkan, meskipun beberapa permintaan belum terlewati.

gambar

Kemungkinan besar, di suatu tempat di bagian bawah halaman beberapa permintaan kembali nilai, dan halaman terus diperbarui dan diterjemahkan secara dinamis, tanpa ketidaknyamanan bagi pengguna.

ES5 dan sebelumnya: Callback


Sebelum melanjutkan dengan tinjauan callback, mari kita lihat / cari tahu apa fungsi dari urutan yang lebih tinggi .

Fungsi tingkat tinggi di JS adalah fungsi yang menggunakan fungsi lain sebagai argumen . Berikut ini sebuah contoh:

objectIsString(objectRef) { return typeof(objectRef) === 'String'; } listOfObjects.filter(objectIsString); 

Dengan demikian, fungsi objectIsString diteruskan ke fungsi tingkat tinggi - filter - yang memungkinkan pemfilteran listOfObjects dan hanya menyisakan objek tipe string dalam daftar.
Callback bekerja dengan cara yang sama. Ini adalah fungsi yang diteruskan sebagai argumen ke fungsi lain. Paling sering, fungsi setTimeout digunakan sebagai contoh fungsi yang memproses panggilan balik. Secara umum, ini digunakan sebagai setTimeout (fungsi, nilai waktu habis), di mana fungsi adalah fungsi panggilan balik yang dijalankan oleh browser setelah periode waktu yang ditentukan dalam batas waktu.

 setTimeout(console.log(1), 2000); console.log(2); 


Cetak 2 1.

ES 6: Janji


Dalam Standar 6, tipe baru diperkenalkan - Janji (janji, selanjutnya - Janji). Janji adalah tipe yang objeknya memiliki satu dari tiga kondisi: tertunda, terpenuhi, ditolak. Selain itu, dengan dua negara terakhir Anda dapat "mengasosiasikan" fungsi - panggilan balik. Segera setelah proses asinkron yang dijelaskan dalam kerangka janji itu sendiri mencapai keberhasilan / kegagalan, fungsi yang terkait dengannya akan dipanggil. Proses ini disebut "menggantung panggilan balik, dan dilakukan menggunakan metode saat itu dan menangkap janji itu sendiri. Perbedaannya adalah bahwa ketika Anda kemudian memanggil argumen, dua fungsi ditransfer - dalam kasus keberhasilan (onFullfillment) dan kegagalan (onRejected), sementara catch menerima, karena tidak sulit ditebak, hanya fungsi untuk memproses kesalahan dalam janji. Untuk menentukan apakah suatu janji berhasil dieksekusi dalam kasus tertentu, serta untuk parameterisasi hasil yang dikembalikan

Mari kita buat dan gunakan janji secara bertahap.

 // : let promise; //     Promise. let promise = new Promise((resolve, reject) => { }); //  ,  . let promise = new Promise((resolve, reject) => { setTimeout(() => { resolve("result"); }, 1000); }); 

Sekarang tambahkan event handler menggunakan metode itu. Argumen ke fungsi yang menangani kesuksesan adalah hasil, sedangkan argumen ke fungsi untuk menangani kegagalan janji adalah kesalahan.

 promise .then( result => { }, error => { } ); //     – . promise .then( result => { //  - -    resolve alert("Fulfilled: " + result); // result -  resolve }, error => { //   -    reject alert("Rejected: " + error); // error -  reject } ); 

Selesai!

Jadi, kami akan menjelaskan sekali lagi proses membuat janji singkat:

  1. Inisialisasi objek (Janji baru)
  2. Kami melewati fungsi tekad dan / atau menolak sebagai satu-satunya argumen kepada konstruktor. Suatu fungsi harus memiliki setidaknya 1 operasi asinkron
  3. Menggunakan metode then / catch, kami menambahkan fungsi - penangan hasil.

Generator. Hasil


Juga dalam standar ES6, jenis fungsi baru didefinisikan - generator. Fungsi-fungsi ini memiliki kemampuan untuk mengembalikan nilai yang berbeda beberapa kali dengan panggilan identik pada pandangan pertama. Mari kita lihat bagaimana mereka melakukannya dan mengapa menggunakannya.

Bentuk standar generator: function * functionName () {}. Dalam tubuh fungsi itu sendiri, kata yield digunakan untuk mengembalikan nilai perantara.

Sebagai contoh, pertimbangkan generator berikut:

 function* generateNumber() { yield 1; yield 2; return 3; } 

Saat ini, generator berada di awal pelaksanaannya. Setiap kali metode generator berikutnya dipanggil, kode yang dijelaskan sebelum hasil berikutnya (atau pengembalian) akan dieksekusi, dan nilai yang ditunjukkan dalam baris dengan salah satu kata ini juga akan dikembalikan.

 Let one = generateNumber.next(); // {value: 1, done: false} 

Panggilan berikutnya akan mengembalikan nilai 2 dengan cara yang sama. Panggilan ketiga akan mengembalikan nilai 3, dan mengakhiri eksekusi fungsi.

 Let two = generateNumber.next(); // {value: 2, done: false} Let three = generateNumber.next(); // {value: 3, done: false} 

Meskipun demikian, generator masih dapat diakses melalui fungsi berikutnya . Namun, itu akan mengembalikan nilai yang sama: objek {done: true}.

ES7. Async / tunggu


Bersama dengan keinginan untuk menyenangkan pecinta OOP dengan bantuan kelas gula sintaksis dan peniruan warisan, para pencipta ES7 berusaha memfasilitasi pemahaman tentang javascript dan bagi mereka yang suka menulis kode sinkron. Menggunakan async / wait constructs, pengguna dapat menulis kode asinkron semirip mungkin dengan sinkron. Jika diinginkan, Anda dapat menyingkirkan janji-janji yang baru dipelajari dan menulis ulang kode dengan sedikit perubahan.
Pertimbangkan sebuah contoh:

Menggunakan Janji:

 requestBook(id) { return bookAPIHelper.getBook(id).then(book => {console.log(book)}); } 

Menggunakan async / tunggu.

 async requestBook(id) { Const book = await bookAPIHelper.getBook(id); Console.log(book); } 

Mari kita gambarkan apa yang kita lihat:

1) Async - kata kunci ditambahkan saat mendeklarasikan fungsi asinkron
2) Tunggu - kata kunci ditambahkan saat memanggil fungsi asinkron.

ES8. Iterasi Asinkron


Iterasi atas data secara serempak menjadi mungkin kembali di ES5. Setelah dua spesifikasi, diputuskan untuk menambahkan kemungkinan iterasi sinkron bekerja di sumber data sinkron. Sekarang, ketika next () dipanggil, ia tidak akan mengembalikan {value, done}, tapi janji (lihat ES6).

Mari kita lihat fungsi createAsyncIterable (iterable).

 async function* createAsyncIterable(iterable) { for (const elem of iterable) { yield elem; } } 

Seperti yang Anda lihat, fungsi menginisialisasi koleksi, untuk setiap panggilan ke elemen-elemen di mana janji akan dikembalikan dengan nilai yang ditentukan dalam iterable.

 const asyncIterable = createAsyncIterable(['async 1', 'async 2']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); asyncIterator.next() .then(result => { console.log(result); // { // value: 'async 1', // done: false, // } return asyncIterator.next(); }) .then(result => { console.log(result); // { // value: 'async 2', // done: false, // } return asyncIterator.next(); }) .then(result => { console.log(result); // { // value: 'undefined', // done: true, // } }); 

Selain itu, standar baru mendefinisikan loop untuk menunggu yang nyaman untuk operasi tersebut.

 for await (const x of createAsyncIterable(['a', 'b'])) 

TL; DR


Sama sekali tidak perlu untuk mengetahui dan mengingat dengan hati versi ECMAScript mana ini atau yang termasuk sintaks, terutama jika Anda baru saja mulai berkenalan dengan perilaku asinkron di JS. Pada saat yang sama, studi asynchrony dalam urutan yang diusulkan oleh sejarah pengembangan spesifikasi akan memungkinkan programmer untuk dengan sempurna memahami sintaks dan instruksi yang diteruskan ke mesin JS, tetapi juga untuk mengikuti logika meningkatkan ECMAScript sebagai produk, untuk memahami tren yang ditentukan oleh pengembang JS, untuk memisahkan mereka dan menerima .

Singkatnya, lalu:

Callback <= ES5
Janji, Hasil (Generator): ES6
Async / tunggu: ES7
Async Iterators: ES8

Source: https://habr.com/ru/post/id434140/


All Articles