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!
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
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:
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');  
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);  
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);  
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);  
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));  
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))  
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 - RasKesimpulan
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!