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 dan verifier(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 mengambil verifier(3,4)pekerjaan tersebut. Janji itu ditolak dan tidak ada panggilan balik untuk itu di verifier(3,4).then(...). Jadi, yang dilakukannya adalah menolak janji yang verifier(3,4).then(...)dikembalikan dan itu menyebabkan verifier(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 menyebabkan response (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 menyebabkan error (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.