JavaScript adalah bahasa sinkron pada intinya, artinya hanya satu baris kode yang berjalan setiap saat. Itu berarti waktu yang dihabiskan untuk mengeksekusi beberapa bagian kode menunda eksekusi kode lainnya. Ini termasuk melukis sesuatu di layar, menangani masukan pengguna, atau mengerjakan matematika Show
Saat membangun aplikasi frontend, kita sering harus berurusan dengan operasi asinkron, seperti input pengguna atau permintaan HTTP. Di browser mereka dapat berjalan di utas terpisah, jadi bagaimana kita menangani asinkronisitas ini dalam bahasa sinkron seperti JavaScript? Memahami bagian JavaScript ini sangat penting untuk membangun aplikasi dunia nyata. Dan itulah yang akan kita lihat di artikel ini Kita akan belajar tentang
📚 Sinkronisitas mengurangi beban kognitif saat menulis kode JavaScript karena Anda tidak perlu khawatir dengan banyak utas yang mengakses dan memperbarui data yang sama. Namun, terkadang perlu keluar dari utas tunggal untuk operasi komputasi yang mahal. Untuk memahami cara mengeksekusi kode Anda sendiri secara asinkron, pelajari tentang Web Worker di browser dan Worker Threads di Node.js. js Fungsi panggilan balikTidak praktis jika membuat permintaan HTTP memblokir kode sampai kami mendapat tanggapan. Bahkan jika itu kembali dalam 100 milidetik, itu masih lama dalam waktu komputer. Untungnya, JavaScript memungkinkan kami menyediakan fungsi panggilan balik ke API asinkron 📌 Callback adalah fungsi yang diteruskan sebagai argumen ke fungsi lain untuk dipanggil oleh fungsi tersebut di lain waktu. Seringkali, untuk menunjukkan bahwa beberapa tindakan telah selesai Bahkan, Anda mungkin menggunakan panggilan balik tanpa memikirkannya Misalnya, kejadian pengguna bersifat asinkron, dan Anda mendaftarkan fungsi callback yang menangani kejadian tersebut, seperti ini Mendaftarkan event handlerKode contoh mendaftarkan panggilan balik untuk dieksekusi ketika pengguna mengklik tombol. Sementara itu, program terus menjalankan kode lain dan tidak menunggu input pengguna 📚 Perlu diketahui bahwa kode event handler mungkin tidak segera dijalankan setelah pengguna mengklik tombol. Pelajari tentang loop peristiwa untuk memahami alasannya Masalah dengan callbackPanggilan balik adalah cara paling dasar untuk menangani kode asinkron. Mereka sebenarnya bisa membuat Anda cukup jauh, tetapi pada titik tertentu, mereka akan mulai merasa membatasi
Pertimbangkan contoh kode JavaScript asinkron ini menggunakan callback Hanya sedalam 3 level, tetapi sarang sudah menjadi berlebihanKodenya tidak terlalu rumit, tapi sudah tidak enak dibaca, karena bersarang. Sekarang pertimbangkan bahwa dalam aplikasi dunia nyata kita perlu sedikit berurusan dengan kode asinkron, dan Anda akan menyadari mengapa segera terasa seperti berada di neraka 😅 Bentuk piramida yang dibentuk oleh callback bersarang ini disebut 'piramida malapetaka', karena lekukannya yang terlihat seperti piramida menyamping JanjiJanji adalah objek JavaScript yang mewakili nilai yang akan tersedia setelah operasi asinkron selesai. Janji dapat dikembalikan secara sinkron seperti nilai biasa, tetapi nilai dapat diberikan di lain waktu Itu juga menyediakan API untuk mengakses nilai "yang dijanjikan" dengan mengikat callback untuk status janji yang berbeda Sintaks konstruktor untuk membuat janji JavaScriptJanji menyatakanBergantung pada hasil operasi asinkron, promise bisa berada dalam tiga status
Janji tertunda selama 1 detik, kemudian dipenuhi dengan nilai string "selesai. "Ketika sebuah janji memasuki keadaan dipenuhi atau ditolak, itu dikatakan diselesaikan. Janji secara formal dikatakan diselesaikan jika diselesaikan atau diselesaikan dengan janji sehingga penyelesaian atau penolakan lebih lanjut tidak ada pengaruhnya. Namun, bahasa sehari-hari sering berarti bahwa janji itu dipenuhi 📚 Jika Anda tertarik dengan definisi formal, lihat spesifikasi Promise/A+ Bekerja dengan janjiJanji bertindak sebagai nilai sinkron - dapat diteruskan sebagai argumen atau dikembalikan oleh fungsi seperti biasa. Namun, untuk membaca nilai akhirnya, Anda perlu "berlangganan" padanya. Untuk memungkinkan itu, janji memiliki metode publik
Beginilah tampilannya dalam praktik Metode utama janji JavaScriptSelama janji tertunda, callback tidak akan dieksekusi. Setelah janji diselesaikan, itu akan selalu memegang nilai hasil. Jika handler dilampirkan ke handler yang sudah diselesaikan, handler langsung lari dan menerima nilai promise Rantai janjiSebuah fitur yang sangat berguna dari promise adalah _4, 5 dan 6 memanggil return promise, yang berarti bahwa kita dapat melampirkan banyak penangan hanya dengan merangkai panggilan bersama-sama Menggabungkan penangan janji bersama-samaSetiap _7 penangan akan menerima hasil yang dikembalikan dari pemanggilan penangan sebelumnya. Jika terjadi kesalahan di salah satu hander, janji akan memasuki status ditolak dan penangan selanjutnya yang dipanggil adalah 8 dan 5Catatan. kesalahan pemula yang umum adalah melampirkan banyak penangan pada janji asli saat mencoba membuat rantai, itu tidak akan berhasil, tetapi ini mungkin fitur yang berguna dalam beberapa kasus Setiap panggilan 4 mengembalikan janji baru dengan nilai yang bertambah, tetapi penangan melekat pada janji asli yang diselesaikan dengan nilai 1Ingat fungsi kita yang membuat teh? Fungsi makeTea ditulis ulang untuk menggunakan promiseTerus terang, itu masih tidak cantik, tetapi ada sedikit sarang dan tidak terus masuk lebih dalam, karena sebagian besar janji dirantai ke janji asli Metode statisJanji memiliki beberapa metode statis untuk membantu mempermudah pengerjaannya. Yang paling penting adalah
Untuk benar-benar memahami cara kerja janji, saya menyarankan Anda untuk memahami cara penerapannya. Saya jamin sebagian besar pengembang frontend tidak akan dapat mengimplementasikan janji, hanya karena mereka tidak memahaminya Nah, sekarang Anda akan melakukannya Menerapkan Basic Promise APIJanji adalah dasar untuk melakukan pekerjaan asinkron dalam JavaScript, jadi sangat penting untuk memahaminya sepenuhnya. Saat saya baru memulai dengan JavaScript, beberapa aspek dari promise tampak ajaib. Namun, itu hanya menunjukkan pemahaman saya yang tidak lengkap Cara terbaik untuk menghilangkan sihir apa pun adalah membangun sesuatu dari awal. Dengan begitu, kita dapat memahami cara kerja berbagai hal di bawah tenda. Percayalah pada saya ketika saya mengatakan ini - jika Anda mempelajari cara menerapkan API janji dari awal, Anda akan memahaminya lebih baik daripada kebanyakan pengembang perangkat lunak Untuk tujuan kami, saya akan menyebut janji kami 0, dengan API yang sama1) TesMari kita mulai dengan menulis beberapa pengujian, sehingga kami yakin bahwa kami mencakup API lengkap. Kami tidak akan menghabiskan waktu di bagian ini, jadi jika Anda mengikuti, cukup salin-tempel kodenya. Kami ingin menguji setidaknya kasus-kasus ini
Inilah test suite yang akan saya gunakan Rangkaian pengujian untuk implementasi janji kustom👉 Jika Anda ingin mengikuti, jangan ragu untuk membuat kode naskah dan kotak dan rekatkan kode ini. Atau garpu tambang dan hapus file 6 jika Anda ingin memulai dari awal. Beralih ke tab "Tes" untuk melihat hasilnya2) AntarmukaSekarang kita beralih ke implementasi, dan hal pertama yang perlu kita lakukan adalah mendefinisikan API publik Metode publik dari implementasi janji kustom kamiSaya mengambil sebagian besar tipe dari definisi tipe janji ES6 sehingga implementasi kami sedekat mungkin dengan standar Konstruktor kami akan mengambil callback sebagai parameter dan menyebutnya lewat fungsi 7 dan 8Ingat bagaimana saya menyebutkan bahwa _2 menerima panggilan balik untuk pemenuhan dan penolakan? . Ini akan menjadi dasar untuk mendaftarkan penangan kami - tangkap dan akhirnya hanya 'gula', seperti yang akan Anda lihat nanti3) Mesin negaraSaya telah menyebutkan bagaimana sebuah janji memiliki 3 status. terpenuhi, ditolak, dan tertunda. Ini dapat dinyatakan sebagai mesin negara Diagram untuk transisi status janjiJanji dimulai sebagai tertunda dan bergerak ke keadaan terselesaikan atau keadaan ditolak. Setelah melakukan transisi, itu tidak dapat lagi diselesaikan, ditolak, atau memasuki status tertunda Untuk mengimplementasikannya, pertama, kita perlu mendefinisikan keadaan internal dan hasil dari promise, mari kita lakukan _0Sekarang kita bisa mengimplementasikan fungsi yang menangani transisi ini _1Metode _0 sekarang bertanggung jawab untuk membuat transisi dan mengatur hasil janji, mari kita pahami apa yang dilakukan kode
📌 Menurut standar janji, jika suatu objek berisi metode 4, maka itu harus bertindak seperti janji, bahkan jika itu bukan turunan dari kelas 5 - itu disebut kemudian dapat. Nah, itu cukup keren. Artinya, kita dapat menyelesaikan _0 dengan 7 sebagai hasilnya dan itu akan tetap berfungsi, dan sebaliknya4) Menyelesaikan / MenolakSekarang kita memiliki fungsi yang menangani transisi status janji kita, kita dapat menggunakannya untuk mengimplementasikan konstruktor dan menyelesaikan/menolak fungsi. Sesederhana memanggil fungsi 0 kami di 7 dan 8 fungsi dan kemudian menggunakannya di konstruktor kami 2Implementasi konstruktor dan menyelesaikan / menolak fungsi janji kustomAnda mungkin memperhatikan blok try-catch dan bertanya-tanya mengapa kami membutuhkannya di konstruktor. Itu karena memanggil _8 bukan satu-satunya cara untuk menolak janji, kita juga bisa 2 kesalahan. Melakukan itu akan memicu _3 blok kami, dan kami menangani kesalahan dengan menolak janjiSekarang kita memiliki kemampuan untuk membuat janji 0 baru dan menjalankan callback. Menyelesaikan atau menolaknya dalam panggilan balik akan mengubah status janji internal dan menetapkan nilainya _3Namun, ada satu masalah 5) Menjalankan janji secara tidak sinkronMembuat janji baru akan segera mengeksekusi callback. Ini berarti bahwa Janji kami memblokir eksekusi kode, yang berarti itu sebenarnya bukan operasi asinkron Jika Anda ingin melihat masalahnya beraksi, jalankan kode ini 4Konstruktor dijalankan secara sinkron, kode asinkron tidak akan segera menjalankan callbackMari kita perbaiki Tanpa mendalami cara kerja loop peristiwa, setidaknya kita harus tahu bahwa kode kita dijalankan secara sinkron dalam fase ini
Artinya dalam praktiknya adalah bahwa kode Anda dijalankan secara sinkron pada prioritas tertinggi - selama itu berjalan, itu akan memblokir eksekusi kode apa pun yang mengikuti. Saat fase eksekusi kode selesai, itu akan memproses semua pekerjaan dan pesan yang telah diterima sementara itu 😉 Jika Anda ingin melihat apa yang saya maksud dengan memblokir kode, jalankan 5 di konsol browser Anda misalnya. Anda tidak akan pernah melihat pesan 'tidak memblokir'. Lakukan dengan risiko Anda sendiri, Anda mungkin tidak dapat menutup tab lagi dan mungkin harus mematikan browserKarena kita sedang melakukan implementasi kustom dari promise, kita berasumsi bahwa tidak ada dukungan asli untuk Promises, tetapi kita masih perlu mengeksekusi callback 0 secara asinkron. Untuk melakukan itu, kita dapat menggunakan peretasan yang terkenal. 7Ini akan mendelegasikan eksekusi panggilan balik untuk dijalankan segera setelah kode sinkron apa pun, karenanya nol milidetik. Mari kita menulis fungsi utilitas 5Menggunakan batas waktu untuk mengeksekusi callback secara asinkronKami sekarang dapat membungkus kode konstruktor dan 8 kami dengan utilitas ini untuk menjalankannya secara asinkron 6Menggunakan utilitas 9 untuk membuat callback kita berjalan secara asinkronJika Anda menguji contoh sebelumnya lagi, Anda akan melihat bahwa ia mencetak 0, yang berarti kode panggilan balik janji tidak segera dijalankan dan tidak lagi memblokir eksekusi kode6) Pelaksana penanganJanji memungkinkan kita untuk mengakses nilainya dengan melampirkan 4 atau 3 penangan dan memberi mereka panggilan balik yang kemudian menerima nilai secara asinkron. Karena callback seharusnya dijalankan satu per satu secara berurutan, kita bisa memasukkannya ke dalam antrian 7Menambahkan antrean internal yang mewakili penangan 4 dan 5 terlampirBagaimana ini akan bekerja
Mari tulis fungsi untuk mengeksekusi handler terlebih dahulu _8A fungsi untuk mengeksekusi 4 dan 5 callback handlerPertama, kita periksa apakah promise sudah terselesaikan, jika belum kita lewati. Kami hanya ingin mengeksekusi penangan _4 dan 5 hanya pada janji yang diselesaikanKemudian kami menjalankan semua penangan untuk _4 atau 5 tergantung pada apakah janji diselesaikan atau ditolak. Setelah itu, kami membersihkan semua penangan agar tidak dieksekusi lagiTerakhir, kita perlu menjalankan resolver segera setelah kita menetapkan hasil dari promise, yang akan menjalankan rantai promise 7) Menerapkan. kemudianKita dapat menjalankan penangan, tetapi kita masih memerlukan cara untuk mendorong penangan ke antrean. Di situlah 4 penangan masuk _9Mendorong penangan ke dalam antrianKodenya terlihat menakutkan, tetapi sebenarnya cukup sederhana saat dipecah Menurut spesifikasi, 4 seharusnya dapat menangani panggilan balik pemenuhan dan penolakan, dan jenisnya berasal langsung dari antarmuka ES6 5. Pawang harus selalu mengembalikan janji sehingga mereka dapat dirantai, sehingga sebagai hasilnya, kami mengembalikan 8Kami mendorong 4 dan 5 penangan, yang pada dasarnya identik, kecuali satu memanggil panggilan balik penyelesaian, dan yang lainnya - tolakKami menyelesaikan janji dengan hasil yang dikembalikan dari panggilan balik. Jika panggilan balik tidak diberikan, kami cukup melewati nilai asli dari janji, yang memungkinkan kami untuk merangkai janji bahkan jika kami menghilangkan salah satu penangan, pada dasarnya menggantinya dengan 7Kemudian kami membungkus semuanya dalam try/catch, karena kami harus dapat menolak janji dengan melemparkan kesalahan pada handler, sebagai alternatif untuk memanggil 8Terakhir, seperti yang disebutkan sebelumnya, kita perlu mengeksekusi penyelesai setelah menambahkan mendorong janji ke dalam antrean, sehingga jika janji sudah diselesaikan, penangan baru akan tetap berjalan Mari kita uji 0Menguji 0 janji kamiJika Anda menjalankan kode ini, Anda akan melihat 04 dan 05, di layar, yang berarti bahwa janji 0 kami dapat dirantai dan dapat menangani pemenuhan dan penolakan8) Menerapkan. menangkap dan. akhirnyaKita sudah memiliki Promise yang berfungsi penuh sekarang, tapi mari kita tambahkan sedikit gula. 5 dan 08Dari tes di atas, Anda dapat melihat, bahwa _3 setara dengan 4 tanpa 11 handler 1Kode untuk 5 handlerDan _6 sesederhana mengeksekusi panggilan balik tidak peduli apakah janji itu dipenuhi atau ditolak 2Kode untuk 6 handlerSatu-satunya peringatan adalah bahwa _6 tidak boleh mengubah status janji, sehingga melewati apa pun hasilnya - mengembalikan nilai jika janji diselesaikan atau mengembalikan kesalahan jika ditolakAnda dapat melihat implementasi lengkapnya di sini Itu dia - implementasi premis dasar yang kami buat sendiri. Sebagai eksperimen yang menyenangkan, coba gunakan secara bergantian dengan janji asli dan lihat apakah berhasil. Jika Anda ingin menyempurnakan implementasi lebih jauh dan memperdalam pemahaman tentang promise, coba terapkan metode statis ini
Asinkron/menungguSekarang Anda mungkin telah mengetahui bahwa janji-janji itu menyelesaikan beberapa masalah bekerja dengan operasi asinkron dalam JavaScript, namun itu tidak sempurna
Nah, baru-baru ini cara yang lebih nyaman untuk menangani operasi asinkron diperkenalkan - async/menunggu, dan janji adalah intinya Fungsi asinkronSaat mendeklarasikan suatu fungsi, kita dapat menandainya sebagai async, yang memungkinkan kita mengembalikan nilai apa pun yang sama seperti biasanya, tetapi hasilnya secara otomatis akan dianggap sebagai janji 3Contoh penggunaan fungsi async di JavaScriptSeperti yang kita lihat di contoh, mengembalikan nilai sama dengan menyelesaikan janji. Sekalipun tidak ada nilai yang dikembalikan, hasilnya tetap janji, kecuali dengan 22 sebagai hasilnya. Demikian pula, melempar kesalahan sama dengan menolak janji 4Contoh menolak janji yang dibuat oleh fungsi async di JavaScriptMenungguApa yang keren tentang fungsi async, apakah di dalamnya Anda dapat menggunakan kata kunci 23 untuk menyelesaikan janji secara sinkron 5Contoh menunggu janji di JavaScriptKata kunci 23 membuat pemblokiran kode sampai janji diselesaikan, pada dasarnya menunggu operasi selesai sampai dilanjutkan dengan eksekusi kode. Ini memungkinkan kita mendapatkan hasil dari fungsi asinkron dengan cara yang hampir sama seperti fungsi biasaTapi bukan itu. Saat Anda menggunakan 23 kesalahan juga akan dilemparkan secara serempak, sehingga blok coba/tangkap biasa akan berfungsi 6Contoh penanganan error yang dilakukan oleh fungsi async di JavaScriptNamun, pada akhirnya, itu semua hanya janji, jadi async/menunggu dapat digunakan dengan 4, 5 dan 6 secara bergantian 7Contoh janji yang digunakan secara bergantian dengan async/menunggu di JavaScriptSebagai latihan terakhir, mari tulis ulang fungsi persiapan teh kita menggunakan async/await 8Contoh persiapan teh menggunakan async/menunggu dan janjiSeperti yang Anda lihat, async/await telah menghilangkan sarang yang berlebihan dan umumnya lebih mudah dibaca dan dipahami PeringatanSeperti yang dapat Anda bayangkan, async/await menyelesaikan sebagian besar masalah yang tersisa dengan promise. Namun, ada beberapa kesalahan umum yang dialami pemula Anda tidak dapat menggunakan 23 di tingkat root atau fungsi biasa, hanya di fungsi asinkron 9Menggunakan menunggu secara tidak benarMeskipun, beberapa runtime JavaScript modern (browser modern, versi simpul terbaru) memungkinkan 30 di tingkat root. Sebagai solusi untuk runtime JS yang lebih lama, gabungkan panggilan dalam fungsi async anonim yang memanggil sendiri 0Fungsi asinkron anonim yang memanggil sendiriPikiran terakhirJavaScript modern menyediakan cara untuk bekerja dengan operasi asinkron dengan mudah. Namun, promise adalah dasar dari segala sesuatu yang asinkron dalam JavaScript, jadi penting untuk memahaminya sepenuhnya Saya telah menunjukkan bagaimana Anda akan mengimplementasikan janji Anda sendiri dan mudah-mudahan, proses tersebut telah menunjukkan kepada Anda bahwa tidak ada keajaiban yang terlibat saat Anda melanggarnya Jika ini adalah keterlibatan pertama Anda dengan janji, Anda mungkin akan sedikit kewalahan, tetapi jangan khawatir, dengan latihan, menggunakan janji akan menjadi kebiasaan, dan Anda selalu dapat menggunakan posting ini sebagai referensi jika Anda ingin meninjau kembali penerapannya Bagaimana Janji semua bekerja secara internal?Janji. all() metode statis mengambil iterable janji sebagai masukan dan mengembalikan satu Janji . Janji yang dikembalikan ini terpenuhi ketika semua janji masukan terpenuhi (termasuk ketika iterable kosong dilewatkan), dengan larik nilai pemenuhan.
Bagaimana Promise bekerja di JavaScript di balik terpal?Itu mengeksekusi panggilan balik dari janji segera. Itu menyusun fungsi yang mengambil nilai Janji masa depan dan mengubahnya untuk mengembalikan Janji baru yang berisi nilai yang diubah. jika Anda mengembalikan Janji dalam a. lalu metode, itu akan meratakannya untuk menghindari Janji bersarang
Bagaimana Janji dijalankan dalam JavaScript?Hanya untuk meninjau, janji dapat dibuat dengan sintaks konstruktor, seperti ini. let promise = new Promise(function(resolve, reject) { // Kode untuk mengeksekusi }); Fungsi konstruktor mengambil fungsi sebagai argumen. Fungsi ini disebut fungsi pelaksana.
Apa yang sebenarnya dipecahkan oleh Janji dalam JavaScript?Anda dapat membaca lebih lanjut tentang sintaks async / await dalam fungsi async dan referensi await. Promise memecahkan cacat mendasar dengan callback piramida malapetaka, dengan menangkap semua kesalahan, bahkan melontarkan pengecualian dan kesalahan pemrograman . Ini penting untuk komposisi fungsional dari operasi asinkron. |