Saat saya memanggil janji ini, hasilnya tidak sesuai dengan urutan pemanggilan fungsi. Itu .then
datang sebelum .catch
, meskipun janji dengan .then
dipanggil setelahnya. Apa alasan untuk itu?
const verifier = (a, b) =>
new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));
verifier(3, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
verifier(5, 4)
.then((response) => console.log("response: ", response))
.catch((error) => console.log("error: ", error));
keluaran
node promises.js
response: true
error: false
javascript
node.js
Gustavo Alves
sumber
sumber
Jawaban:
Ini adalah pertanyaan yang bagus untuk digali.
Saat Anda melakukan ini:
verifier(3,4).then(...)
yang mengembalikan promise baru yang memerlukan siklus lain kembali ke loop peristiwa sebelum promise yang baru ditolak itu bisa menjalankan
.catch()
penangan yang mengikutinya. Siklus ekstra itu memberikan urutan berikutnya:verifier(5,4).then(...)
kesempatan untuk menjalankan
.then()
penangannya sebelum baris sebelumnya.catch()
karena sudah ada dalam antrian sebelum.catch()
penangan dari yang pertama masuk ke antrian dan item dijalankan dari antrian dalam urutan FIFO.Perhatikan, jika Anda menggunakan
.then(f1, f2)
formulir sebagai pengganti.then().catch()
, itu berjalan seperti yang Anda harapkan karena tidak ada janji tambahan dan dengan demikian tidak ada tanda centang tambahan yang terlibat:const verifier = (a, b) => new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false))); verifier(3, 4) .then((response) => console.log("response (3,4): ", response), (error) => console.log("error (3,4): ", error) ); verifier(5, 4) .then((response) => console.log("response (5,4): ", response)) .catch((error) => console.log("error (5,4): ", error));
Catatan, saya juga memberi label pada semua pesan sehingga Anda dapat melihat dari
verifier()
panggilan mana mereka berasal yang membuatnya lebih mudah untuk membaca hasilnya.ES6 Spec tentang pemesanan panggilan balik janji dan penjelasan lebih detail
Spesifikasi ES6 memberi tahu kita bahwa promise "jobs" (karena memanggil callback dari a
.then()
atau.catch()
) dijalankan dalam urutan FIFO berdasarkan pada saat mereka dimasukkan ke dalam antrean pekerjaan. Itu tidak secara khusus menyebut FIFO, tetapi menentukan bahwa pekerjaan baru dimasukkan di akhir antrian dan pekerjaan dijalankan dari awal antrian. Itu mengimplementasikan pemesanan FIFO.PerformPromiseThen (yang mengeksekusi callback dari
.then()
) akan mengarah ke EnqueueJob yang merupakan cara penanganan penyelesaian atau penolakan dijadwalkan untuk dijalankan. EnqueueJob menetapkan bahwa pekerjaan yang tertunda ditambahkan di belakang antrian pekerjaan. Kemudian operasi NextJob menarik item dari depan antrian. Ini memastikan urutan FIFO dalam melayani pekerjaan dari antrian pekerjaan Promise.Jadi, dalam contoh di pertanyaan awal, kita mendapatkan callback untuk
verifier(3,4)
promise danverifier(5,4)
promise dimasukkan ke dalam antrean pekerjaan sesuai urutan dijalankannya karena kedua promise asli tersebut sudah selesai. Kemudian, saat penafsir kembali ke loop peristiwa, pertama kali penafsir mengambilverifier(3,4)
pekerjaan tersebut. Janji itu ditolak dan tidak ada panggilan balik untuk itu diverifier(3,4).then(...)
. Jadi, yang dilakukannya adalah menolak janji yangverifier(3,4).then(...)
dikembalikan dan itu menyebabkanverifier(3,4).then(...).catch(...)
penangan dimasukkan ke dalam jobQueue.Kemudian, ia kembali ke loop peristiwa dan pekerjaan berikutnya yang ditariknya dari jobQueue adalah
verifier(5, 4)
pekerjaan tersebut. Itu memiliki janji terselesaikan dan penangan tekad sehingga memanggil penangan itu. Ini menyebabkanresponse (5,4):
keluaran ditampilkan.Kemudian, ia kembali ke loop peristiwa dan pekerjaan berikutnya yang ditarik dari jobQueue adalah
verifier(3,4).then(...).catch(...)
pekerjaan tempat menjalankannya dan ini menyebabkanerror (3,4)
keluaran ditampilkan.Itu karena
.catch()
rantai di rantai pertama adalah satu tingkat janji lebih dalam di rantainya daripada.then()
di rantai kedua yang menyebabkan pengurutan yang Anda laporkan. Dan, itu karena rantai perjanjian dilintasi dari satu tingkat ke tingkat berikutnya melalui antrean pekerjaan dalam urutan FIFO, tidak sinkron.Rekomendasi Umum Tentang Mengandalkan Tingkat Detail Penjadwalan Ini
FYI, secara umum, saya mencoba menulis kode yang tidak bergantung pada tingkat pengetahuan pengaturan waktu yang terperinci ini. Meskipun penasaran dan terkadang berguna untuk dipahami, ini adalah kode yang rapuh karena perubahan sederhana yang tampaknya tidak berbahaya pada kode dapat menyebabkan perubahan dalam waktu relatif. Jadi, jika pengaturan waktu sangat penting antara dua rantai seperti ini, maka saya lebih suka menulis kode dengan cara yang memaksa waktu seperti yang saya inginkan daripada bergantung pada tingkat pemahaman terperinci ini.
sumber
.then()
harus mengembalikan janji baru yang harus diselesaikan / ditolak secara asinkron pada waktu mendatang yang mengarah ke pemesanan ini. Apakah Anda mengetahui penerapan yang tidak menggunakan pengurutan FIFO untuk panggilan balik yang bersaing?await
, meskipun).PerformPromiseThen
akan mengarah keEnqueueJob
mana penanganan menyelesaikan atau menolak dijadwalkan untuk dipanggil. EnqueueJob menetapkan bahwa pekerjaan yang tertunda ditambahkan di belakang antrian pekerjaan. Kemudian operasi NextJob menarik item dari depan antrian. Ini memastikan urutan FIFO dalam antrian pekerjaan Promise.await
dalam ES11 ini? Tautan sudah cukup. Terima kasih!!Promise.resolve() .then(() => console.log('a1')) .then(() => console.log('a2')) .then(() => console.log('a3')) Promise.resolve() .then(() => console.log('b1')) .then(() => console.log('b2')) .then(() => console.log('b3'))
Alih-alih output a1, a2, a3, b1, b2, b3 Anda akan melihat a1, b1, a2, b2, a3, b3 karena alasan yang sama - setiap kemudian mengembalikan sebuah janji dan pergi ke akhir event-loop antre. Jadi kita bisa melihat "perlombaan janji" ini. Hal yang sama terjadi ketika ada beberapa janji bertingkat.
sumber