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