JavaScript Asinkron: Penjelasan panggilan balik dan janji

Berurusan dengan kode asinkron, yang berarti kode yang tidak langsung dieksekusi seperti permintaan web atau pengatur waktu, bisa jadi rumit. JavaScript memberi kita dua cara untuk menangani perilaku asinkron: callback dan janji.

Callback adalah satu-satunya cara yang didukung secara native untuk menangani kode asinkron hingga 2016, saat Promiseobjek diperkenalkan ke bahasa tersebut. Namun, pengembang JavaScript telah menerapkan fungsi serupa pada tahun-tahun mereka sendiri sebelum janji muncul. Mari kita lihat beberapa perbedaan antara panggilan balik dan janji, dan lihat bagaimana kami menangani koordinasi beberapa janji.

Fungsi asinkron yang menggunakan callback mengambil fungsi sebagai parameter, yang akan dipanggil setelah pekerjaan selesai. Jika Anda telah menggunakan sesuatu seperti setTimeoutdi browser, Anda telah menggunakan panggilan balik.

// Anda dapat menentukan panggilan balik Anda secara terpisah ...

biarkan myCallback = () => {

  console.log ('Disebut!');

};

setTimeout (myCallback, 3000);

//… tapi itu juga umum untuk melihat callback didefinisikan sebaris

setTimeout (() => {

  console.log ('Disebut!');

}, 3000);

Biasanya fungsi yang menerima callback menganggapnya sebagai argumen terakhirnya. Ini bukan kasus di atas, jadi anggaplah ada fungsi baru yang disebut waityang sama setTimeouttetapi menggunakan dua argumen pertama dalam urutan yang berlawanan:

// Kami akan menggunakan fungsi baru kami seperti ini:

waitCallback (3000, () => {

  console.log ('Disebut!');

});

Callback bersarang dan piramida malapetaka

Callback berfungsi dengan baik untuk menangani kode asinkron, tetapi menjadi rumit saat Anda mulai harus mengoordinasikan beberapa fungsi asinkron. Misalnya, jika kita ingin menunggu dua detik dan mencatat sesuatu, lalu menunggu tiga detik dan mencatat sesuatu yang lain, lalu menunggu empat detik dan mencatat sesuatu yang lain, sintaks kita menjadi sangat bersarang.

// Kami akan menggunakan fungsi baru kami seperti ini:

waitCallback (2000, () => {

  console.log ('First Callback!');

  waitCallback (3000, () => {

    console.log ('Panggilan Balik Kedua!');

    waitCallback (4000, () => {

      console.log ('Panggilan Balik Ketiga!');

    });

  });

});

Ini mungkin tampak seperti contoh yang sepele (dan memang demikian), tetapi tidak jarang membuat beberapa permintaan web berturut-turut berdasarkan hasil kembalian dari permintaan sebelumnya. Jika pustaka AJAX Anda menggunakan callback, Anda akan melihat struktur di atas dimainkan. Dalam contoh yang lebih dalam bersarang, Anda akan melihat apa yang disebut sebagai piramida malapetaka, yang namanya berasal dari bentuk piramida yang dibuat di spasi putih menjorok di awal baris.

Seperti yang Anda lihat, kode kami menjadi rusak secara struktural dan lebih sulit dibaca saat berhadapan dengan fungsi asinkron yang perlu terjadi secara berurutan. Tapi itu semakin rumit. Bayangkan jika kita ingin memulai tiga atau empat permintaan web dan melakukan beberapa tugas hanya setelah semuanya kembali. Saya mendorong Anda untuk mencoba melakukannya jika Anda belum pernah menghadapi tantangan sebelumnya.

Asinkronisasi yang lebih mudah dengan janji

Promises memberikan API yang lebih fleksibel untuk menangani tugas-tugas asinkron. Ini membutuhkan fungsi yang ditulis sedemikian rupa sehingga mengembalikan sebuah Promiseobjek, yang memiliki beberapa fitur standar untuk menangani perilaku selanjutnya dan mengkoordinasikan beberapa janji. Jika waitCallbackfungsi kita Promiseberbasis, itu hanya akan membutuhkan satu argumen, yang merupakan milidetik untuk menunggu. Fungsi selanjutnya akan terikat janji. Contoh pertama kita akan terlihat seperti ini:

biarkan myHandler = () => {

  console.log ('Disebut!');

};

waitPromise (3000). lalu (myHandler);

Dalam contoh di atas, waitPromise(3000)mengembalikan Promiseobjek yang memiliki beberapa metode untuk kita gunakan, seperti then. Jika kita ingin menjalankan beberapa fungsi asinkron satu demi satu, kita bisa menghindari piramida malapetaka dengan menggunakan promise. Kode itu, yang ditulis ulang untuk mendukung janji baru kami, akan terlihat seperti ini:

// Tidak peduli berapa banyak tugas asinkron berurutan yang kita miliki, kita tidak pernah membuat piramida.

waitPromise (2000)

  .then (() => {

    console.log ('First Callback!');

    return waitPromise (3000);

  })

  .then (() => {

    console.log ('Panggilan Balik Kedua!');

    return waitPromise (4000);

  })

  .then (() => {

    console.log ('Panggilan Balik Kedua!');

    return waitPromise (4000);

  });

Lebih baik lagi, jika kita perlu mengoordinasikan tugas asinkron yang mendukung Promises, kita dapat menggunakan allmetode statis pada Promiseobjek yang mengambil beberapa promise dan menggabungkannya menjadi satu. Itu akan terlihat seperti:

Promise.all ([

  waitPromise (2000),

  waitPromise (3000),

  waitPromise (4000)

]). then (() => console.log ('Semuanya selesai!'));

Minggu depan, kita akan menggali lebih jauh tentang cara kerja promise dan cara menggunakannya secara idiomatis. Jika Anda baru belajar JavaScript atau tertarik untuk menguji pengetahuan Anda, cobalah waitCallbackatau coba lakukan yang setara Promise.alldengan callback.

Seperti biasa, hubungi saya di Twitter jika ada komentar atau pertanyaan.