Memahami Janji JavaScript

Selamat siang, Habr! Saya mempersembahkan kepada Anda terjemahan artikel “Memahami Janji dalam JavaScript” oleh Sukhjinder Arora.



Dari penulis terjemahan: Serta penulis sendiri, saya berharap artikel itu bermanfaat bagi Anda. Tolong, jika dia benar-benar membantu Anda mempelajari sesuatu yang baru untuk diri sendiri, maka jangan terlalu malas untuk pergi ke artikel asli dan berterima kasih kepada penulis! Saya akan senang atas tanggapan Anda!

Tautan ke terjemahan artikel pada JavaScript asinkron dari penulis yang sama .

JavaScript adalah bahasa pemrograman single-threaded, yang berarti bahwa satu hal dapat dilakukan sekaligus. Sebelum ES6, kami menggunakan panggilan balik untuk mengelola tugas yang tidak sinkron, seperti permintaan jaringan.

Dengan menggunakan janji, kita dapat menghindari "panggilan balik neraka" dan membuat kode kita lebih bersih, lebih mudah dibaca, dan lebih mudah dipahami.

Misalkan kita ingin mendapatkan beberapa data dari server secara tidak sinkron, menggunakan callback kita akan melakukan sesuatu seperti ini:

getData(function(x){ console.log(x); getMoreData(x, function(y){ console.log(y); getSomeMoreData(y, function(z){ console.log(z); }); }); }); 

Di sini, saya meminta beberapa data dari server menggunakan fungsi getData () , yang menerima data di dalam fungsi panggilan balik. Di dalam fungsi callback, saya meminta data tambahan dengan memanggil fungsi getMoreData () , meneruskan data sebelumnya sebagai argumen, dan sebagainya.

Ini adalah apa yang kita sebut "panggilan balik neraka," di mana setiap panggilan balik bersarang di dalam yang lain, dan setiap panggilan balik internal tergantung pada orang tuanya.

Kami dapat menulis ulang cuplikan di atas menggunakan janji:

 getData() .then((x) => { console.log(x); return getMoreData(x); }) .then((y) => { console.log(y); return getSomeMoreData(y); }) .then((z) => { console.log(z); }); 

Anda dapat melihat apa yang menjadi lebih mudah dibaca daripada dengan contoh panggilan balik pertama.

Apa itu Janji?


Janji (Promise) adalah objek yang berisi nilai operasi asinkron di masa depan. Misalnya, jika Anda meminta beberapa data dari server, Promis berjanji kepada kami untuk menerima data ini, yang dapat kami gunakan di masa mendatang.

Sebelum menyelam ke semua hal teknis ini, mari kita lihat terminologi janji.

Negara janji


Janji dalam JavaScript, seperti janji dalam kehidupan nyata, memiliki 3 status. Ini bisa 1) tidak terselesaikan (tertunda), 2) diselesaikan / diselesaikan (selesai) atau 3) ditolak / ditolak.



Unresolved or Pending - Promis menunggu jika hasilnya tidak siap. Artinya, ia mengharapkan penyelesaian sesuatu (misalnya, penyelesaian operasi asinkron).
Diselesaikan atau Selesai - Promis diselesaikan jika hasilnya tersedia. Artinya, sesuatu menyelesaikan eksekusi (misalnya, operasi asinkron) dan semuanya berjalan dengan baik.
Ditolak - Promis ditolak jika terjadi kesalahan selama eksekusi.

Sekarang kita tahu apa itu Promis dan terminologinya, mari kita kembali ke bagian praktis dari janji.

Buat Promis


Dalam kebanyakan kasus, Anda hanya akan menggunakan janji, bukan menciptakannya, tetapi masih penting untuk mengetahui bagaimana mereka dibuat.

Sintaks:

 const promise = new Promise((resolve, reject) => { ... }); 

Kami menciptakan janji baru menggunakan konstruktor Janji, dibutuhkan satu argumen, panggilan balik, juga dikenal sebagai fungsi eksekutif, yang mengambil 2 panggilan balik, menyelesaikan dan menolak .

Fungsi eksekutif dilakukan segera setelah penciptaan janji. Sebuah janji dibuat dengan memanggil tekad () , dan ditolak dengan tolak () . Sebagai contoh:

 const promise = new Promise((resolve, reject) => { if(allWentWell) { resolve('  !'); } else { reject('-   '); } }); 

menyelesaikan () dan menolak () mengambil satu argumen, yang bisa berupa string, angka, ekspresi logis, array, atau objek.

Mari kita lihat contoh lain untuk sepenuhnya memahami bagaimana janji dibuat.

 const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); setTimeout(() => { if(randomNumber < .6) { resolve('  !'); } else { reject('-   '); } }, 2000); }); 

Di sini saya membuat Janji baru menggunakan konstruktor Promis. Sebuah janji dieksekusi atau ditolak 2 detik setelah pembuatannya. Janji dijalankan jika RandomNumber kurang dari 0,6 dan ditolak dalam kasus lain.

Ketika sebuah janji telah dibuat, itu akan ditangguhkan dan nilainya tidak akan ditentukan .


Setelah 2 detik, penghitung waktu berakhir, janji dijalankan atau ditolak secara acak, dan nilainya akan diteruskan ke fungsi tekad atau tolak . Di bawah ini adalah contoh dari dua kasus:

Penyelesaian yang berhasil:



Penolakan janji:



Catatan: Janji dapat dieksekusi atau ditolak hanya sekali. Panggilan lebih lanjut untuk menyelesaikan () atau menolak () tidak akan memengaruhi kondisi janji dengan cara apa pun. Contoh:

 const promise = new Promise((resolve, reject) => { resolve('Promise resolved'); //   reject('Promise rejected'); //       }); 

Karena tekad () dipanggil terlebih dahulu, janji tersebut sekarang memiliki status "selesai". Panggilan selanjutnya untuk menolak () tidak akan mempengaruhi keadaan janji dengan cara apa pun.

Menggunakan Promis


Sekarang kita tahu cara membuat janji, sekarang mari kita cari tahu cara menerapkan janji yang sudah dibuat. Kami menggunakan janji menggunakan metode then () dan catch () .

Misalnya, meminta data dari API menggunakan fetch , yang mengembalikan janji.

.then () sintaks: janji.then (successCallback, failureCallback)

successCallback dipanggil jika janji telah berhasil dieksekusi. Dibutuhkan satu argumen, yang merupakan nilai yang diteruskan untuk menyelesaikan () .

failCallback dipanggil jika janji telah ditolak. Dibutuhkan satu argumen, yang merupakan nilai yang diberikan untuk menolak () .

Contoh:

 const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); if(randomNumber < .7) { resolve('  !'); } else { reject(new Error('-   ')); } }); promise.then((data) => { console.log(data); //  '  !' }, (error) => { console.log(error); //   } ); 

Jika janji itu dieksekusi, successCallback dipanggil dengan nilai yang diteruskan untuk menyelesaikan () . Dan jika janji itu ditolak, maka kegagalanCallback disebut dengan nilai yang diteruskan untuk menolak ().

sintaks .catch () : janji.catch (failureCallback)

Kami menggunakan catch () untuk menangani kesalahan. Ini lebih mudah dibaca daripada penanganan kesalahan di dalam failureCallback di dalam metode callback then () .

 const promise = new Promise((resolve, reject) => { reject(new Error('-   ')); }); promise .then((data) => { console.log(data); }) .catch((error) => { console.log(error); //   }); 

Rantai Janji


Metode then () dan catch () juga dapat mengembalikan janji baru, yang dapat diproses oleh rantai selain () di akhir metode then () sebelumnya.

Kami menggunakan rantai janji ketika kami ingin menyelesaikan serangkaian janji.

Sebagai contoh:

 const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1 .then((data) => { console.log(data); // Promise1  return promise2; }) .then((data) => { console.log(data); // Promise2  return promise3; }) .then((data) => { console.log(data); }) .catch((error) => { console.log(error); // Promise3  }); 

Jadi apa yang terjadi di sini?


Ketika janji1 terpenuhi, maka metode () dipanggil , yang mengembalikan janji2.
Selanjutnya, ketika janji2 dipenuhi , maka () dipanggil lagi dan mengembalikan janji3 .

Karena janji3 ditolak, alih-alih selanjutnya () , tangkapan () disebut, yang menangani penolakan janji3 .

Catatan: Sebagai aturan, satu metode catch () cukup untuk menangani penolakan terhadap salah satu janji dalam rantai jika metode ini ada di akhir.

Kesalahan umum


Cukup banyak pendatang baru membuat kesalahan dengan menginvestasikan beberapa janji di dalam yang lain. Sebagai contoh:

 const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1.then((data) => { console.log(data); // Promise1  promise2.then((data) => { console.log(data); // Promise2  promise3.then((data) => { console.log(data); }).catch((error) => { console.log(error); // Promise3  }); }).catch((error) => { console.log(error); }) }).catch((error) => { console.log(error); }); 

Meskipun ini akan berfungsi dengan baik, itu dianggap gaya yang buruk dan membuat kode lebih mudah dibaca. Jika Anda memiliki urutan janji untuk dieksekusi, akan lebih baik untuk menempatkan mereka satu demi satu daripada menempatkan satu di dalam yang lain.

Promise.all ()


Metode ini mengambil berbagai janji dan mengembalikan janji baru yang akan dieksekusi ketika semua janji di dalam array dieksekusi atau ditolak segera setelah janji yang ditolak ditemukan. Sebagai contoh:

 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error)); 

Di sini, argumen di dalamnya then () adalah array yang berisi nilai-nilai janji dalam urutan yang sama di mana mereka diteruskan ke Promise.all () . (Hanya jika semua janji dieksekusi)

Janji itu ditolak dengan alasan penolakan dari janji pertama dalam array yang ditransfer. Sebagai contoh:

 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error)); // Promise2  

Di sini kita memiliki dua janji, di mana satu dieksekusi setelah 2 detik dan yang lainnya menyimpang setelah 1,5 detik. Segera setelah janji kedua ditolak, janji yang dikembalikan dari Promise.all () ditolak tanpa menunggu yang pertama.

Metode ini dapat berguna ketika Anda memiliki lebih dari satu janji dan Anda ingin tahu kapan semua janji dipenuhi. Misalnya, jika Anda meminta data dari API pihak ketiga dan Anda ingin melakukan sesuatu dengan data ini hanya ketika semua permintaan berhasil.

Akibatnya, kami memiliki Promise.all () , yang menunggu eksekusi yang sukses dari semua janji, atau menyelesaikan eksekusi ketika mendeteksi kegagalan pertama dalam serangkaian janji.

Promise.race ()


Metode ini menerima berbagai janji dan mengembalikan satu janji baru yang akan dieksekusi segera setelah janji yang dipenuhi dalam array dipenuhi atau ditolak jika janji yang ditolak terjadi sebelumnya. Sebagai contoh:

 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.race([promise1, promise2]) .then((data) => console.log(data)) // Promise1  .catch((error) => console.log(error)); 

Di sini kita memiliki dua janji, di mana satu dieksekusi setelah 1 detik, dan yang lainnya menyimpang setelah 1,5 detik. Segera setelah janji pertama dipenuhi, janji yang dikembalikan dari Promise.race () akan memiliki status dipenuhi tanpa menunggu status janji kedua.

Di sini, data yang diteruskan ke then () adalah nilai dari janji yang dieksekusi pertama kali.

Akibatnya, Promise.race () menunggu janji pertama dan mengambil statusnya sebagai status janji yang dikembalikan.

Komentar oleh penulis terjemahan: Oleh karena itu nama itu sendiri. Ras - Ras

Kesimpulan


Kami mempelajari apa itu janji dan apa yang mereka makan dalam JavaScript. Janji terdiri dari dua bagian 1) Buat janji dan 2) Gunakan janji. Sebagian besar waktu Anda akan menggunakan janji daripada membuatnya, tetapi penting untuk mengetahui bagaimana mereka dibuat.

Itu saja, saya harap artikel ini bermanfaat bagi Anda!

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


All Articles