Saya telah mengembangkan JavaScript selama beberapa tahun dan saya tidak mengerti apa-apa tentang janji.
Sepertinya yang saya lakukan hanyalah perubahan:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
Yang mana saya bisa menggunakan pustaka seperti async , dengan sesuatu seperti:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Kode yang lebih banyak dan lebih sedikit dibaca. Saya tidak mendapatkan apa-apa di sini, tidak secara mendadak 'datar' juga. Belum lagi harus mengubah hal-hal menjadi janji.
Jadi, apa masalah besar tentang janji di sini?
Jawaban:
Janji bukan panggilan balik. Sebuah janji mewakili hasil operasi asinkron di masa depan . Tentu saja, menuliskannya seperti yang Anda lakukan, Anda mendapat sedikit manfaat. Tetapi jika Anda menuliskannya dengan cara yang seharusnya digunakan, Anda dapat menulis kode asinkron dengan cara yang menyerupai kode sinkron dan jauh lebih mudah diikuti:
Tentu saja, tidak jauh lebih sedikit kode, tetapi jauh lebih mudah dibaca.
Tapi ini bukan akhirnya. Mari kita temukan manfaat sebenarnya: Bagaimana jika Anda ingin memeriksa kesalahan dalam salah satu langkah? Akan sangat sulit untuk melakukannya dengan panggilan balik, tetapi dengan janji, adalah sepotong kue:
Sama seperti
try { ... } catch
balok.Bahkan lebih baik:
Dan bahkan lebih baik: Bagaimana jika mereka 3 panggilan ke
api
,api2
,api3
bisa dijalankan secara bersamaan (misalnya jika mereka panggilan AJAX) tetapi Anda harus menunggu untuk tiga? Tanpa janji, Anda harus membuat semacam penghitung. Dengan janji-janji, menggunakan notasi ES6, adalah sepotong kue dan cukup rapi:Semoga Anda melihat Janji dalam cahaya baru sekarang.
sumber
api2
danapi3
? apakah yang terakhir.then
hanya akan dipanggil setelah operasi async selesai?Ya, Janji adalah panggilan balik yang tidak sinkron. Mereka tidak dapat melakukan apa pun yang tidak bisa dilakukan panggilan balik, dan Anda menghadapi masalah yang sama dengan asinkron seperti halnya dengan panggilan balik biasa.
Namun, Janji lebih dari sekadar panggilan balik. Mereka adalah abstraksi yang sangat perkasa, memungkinkan kode fungsional lebih bersih dan lebih baik dengan boilerplate yang lebih rentan kesalahan.
Janji adalah objek yang mewakili hasil perhitungan tunggal (tidak sinkron). Mereka menyelesaikan hasil itu hanya sekali. Ada beberapa hal yang artinya:
Janji menerapkan pola pengamat:
return
menjadi objek JanjiJanji-janji tidak dapat ditagih ( monadik , jika Anda mau ):
.then()
metode ini. Dibutuhkan panggilan balik untuk dipanggil dengan hasil pertama, dan mengembalikan janji untuk hasil janji bahwa panggilan balik kembali.Kedengarannya rumit? Waktu untuk contoh kode.
Meratakan tidak datang secara ajaib, tetapi Anda dapat dengan mudah melakukannya. Untuk contoh Anda yang sangat bersarang, yang setara (dekat) akan menjadi
Jika melihat kode dari metode ini membantu memahami, inilah janji paling mendasar dalam beberapa baris .
Abstraksi Janji memungkinkan kompabilitas fungsi yang jauh lebih baik. Sebagai contoh, di sebelah
then
untuk chaining,all
fungsi menciptakan janji untuk hasil gabungan dari janji-janji paralel ganda.Last but not least Janji datang dengan penanganan kesalahan terintegrasi. Hasil perhitungannya bisa berupa apakah janji itu dipenuhi dengan nilai, atau ditolak dengan alasan. Semua fungsi komposisi menangani ini secara otomatis dan menyebarkan kesalahan dalam rantai janji, sehingga Anda tidak perlu mempedulikannya secara eksplisit di mana-mana - berbeda dengan implementasi panggilan balik biasa. Pada akhirnya, Anda dapat menambahkan callback kesalahan khusus untuk semua pengecualian yang terjadi.
Itu cukup sepele sebenarnya dengan perpustakaan janji yang baik, lihat Bagaimana cara mengonversi API panggilan balik yang ada ke janji?
sumber
.then(console.log)
, karena console.log tergantung pada konteks konsol. Dengan cara ini akan menyebabkan kesalahan doa ilegal. Gunakanconsole.log.bind(console)
ataux => console.log(x)
untuk mengikat konteks.console
metode sudah terikat. Dan tentu saja, saya hanya mengatakan bahwa kedua sarang memiliki perilaku yang persis sama, tidak ada di antara mereka yang bekerja:Selain jawaban yang sudah ada, dengan fungsi panah ES6, Janji berubah dari kerdil biru kecil yang bersinar lurus menjadi raksasa merah. Itu akan runtuh menjadi supernova:
Seperti yang ditunjukkan oligofren , tanpa argumen antara panggilan api, Anda tidak memerlukan fungsi pembungkus anonim sama sekali:
Dan akhirnya, jika Anda ingin mencapai level lubang hitam supermasif, Janji bisa ditunggu:
sumber
apiX
metode, Anda mungkin juga melewatkan fungsi panah sama sekali:api().then(api2).then(api3).then(r3 => console.log(r3))
.Selain jawaban luar biasa di atas, 2 poin lagi dapat ditambahkan:
1. Perbedaan semantik:
Janji mungkin sudah diselesaikan pada saat penciptaan. Ini berarti mereka menjamin kondisi daripada peristiwa . Jika sudah dipecahkan, fungsi yang diselesaikan yang diteruskan ke sana masih dipanggil.
Sebaliknya, panggilan balik menangani acara. Jadi, jika acara yang Anda minati telah terjadi sebelum callback terdaftar, callback tidak dipanggil.
2. Pembalikan kontrol
Callback melibatkan inversi kontrol. Ketika Anda mendaftarkan fungsi panggilan balik dengan API apa pun, runtime Javascript menyimpan fungsi panggilan balik dan memanggilnya dari loop acara setelah siap dijalankan.
Lihat loop Acara Javascript untuk penjelasan.
Dengan Janji , kendali berada dengan program panggilan. Metode .then () dapat dipanggil kapan saja jika kita menyimpan objek janji.
sumber
Selain jawaban lain, sintaksis ES2015 berpadu mulus dengan janji-janji, mengurangi lebih banyak lagi kode boilerplate:
sumber
Janji bukan panggilan balik, keduanya adalah idiom pemrograman yang memfasilitasi pemrograman async. Menggunakan gaya pemrograman async / menunggu menggunakan coroutine atau generator yang mengembalikan janji dapat dianggap sebagai idiom ketiga. Perbandingan idiom-idiom ini di berbagai bahasa pemrograman (termasuk Javascript) ada di sini: https://github.com/KjellSchubert/promise-future-task
sumber
Tidak, tidak sama sekali.
Callback hanyalah Fungsi Dalam JavaScript yang harus dipanggil dan kemudian dieksekusi setelah eksekusi fungsi lain selesai. Jadi bagaimana itu terjadi?
Sebenarnya, dalam JavaScript, fungsi itu sendiri dianggap sebagai objek dan karenanya sebagai semua objek lain, bahkan fungsi dapat dikirim sebagai argumen ke fungsi lain . Kasus penggunaan paling umum dan umum yang dapat dipikirkan seseorang adalah fungsi setTimeout () dalam JavaScript.
Janji hanyalah pendekatan yang jauh lebih improvisasi dari penanganan dan penataan kode asinkron dibandingkan dengan melakukan hal yang sama dengan panggilan balik.
Janji menerima dua Callback dalam fungsi konstruktor: menyelesaikan dan menolak. Panggilan balik dalam janji ini memberi kami kendali yang baik atas penanganan kesalahan dan kasus sukses. Resolve callback digunakan ketika eksekusi janji dilakukan dengan sukses dan penolakan panggilan balik digunakan untuk menangani kasus kesalahan.
sumber
Tidak ada janji yang hanya dibungkus dengan panggilan balik
contoh Anda dapat menggunakan javascript asli yang dijanjikan dengan simpul js
sumber
Javascript Janji sebenarnya menggunakan fungsi callback untuk menentukan apa yang harus dilakukan setelah Janji telah diselesaikan atau ditolak, oleh karena itu keduanya tidak berbeda secara mendasar. Gagasan utama di balik Janji adalah untuk mengambil panggilan balik - terutama panggilan balik bersarang di mana Anda ingin melakukan semacam tindakan, tetapi itu akan lebih mudah dibaca.
sumber
Ikhtisar janji:
Di JS kita bisa membungkus operasi asinkron (misalnya panggilan basis data, panggilan AJAX) dengan janji. Biasanya kami ingin menjalankan beberapa logika tambahan pada data yang diambil. Janji-janji JS memiliki fungsi handler yang memproses hasil dari operasi asinkron. Fungsi handler bahkan dapat memiliki operasi asinkron lain di dalamnya yang dapat mengandalkan nilai operasi asinkron sebelumnya.
Sebuah janji selalu memiliki 3 negara berikut:
Janji yang tertunda dapat diselesaikan / dipenuhi atau ditolak dengan suatu nilai. Kemudian metode handler berikut yang menerima panggilan balik sebagai argumen disebut:
Promise.prototype.then()
: Ketika janji terselesaikan argumen callback dari fungsi ini akan dipanggil.Promise.prototype.catch()
: Ketika janji ditolak, argumen callback dari fungsi ini akan dipanggil.Meskipun keterampilan metode di atas mendapatkan argumen callback mereka jauh lebih unggul daripada hanya menggunakan callback di sini adalah contoh yang akan banyak menjelaskan:
Contoh
then
metode pertama dipanggil dan nilai terselesaikan dilewatkan sebagai argumen dari callbackcatch
metode pertama dipanggil dan nilai yang ditolak diteruskan sebagai argumencatch
danthen
mengembalikan janji itu sebabnya kita bisa rantai mereka. MerekaPromise.resolve
memasukkan nilai yang dikembalikan dan nilai yang dilemparkan (menggunakanthrow
kata kunci) diPromise.reject
. Jadi setiap nilai yang dikembalikan ditransformasikan menjadi sebuah janji dan pada janji ini kita dapat lagi memanggil fungsi penangan.catch
metode ini menangani semua kesalahan yang terjadi sebelumcatch
penangan.sumber