Когда приходит время вызвать обратный вызов, задание вообще не go в стандартной очереди заданий (ScriptJobs); это идет в очередь PromiseJobs. Очередь PromiseJobs обрабатывается до тех пор, пока она не станет пустой, когда заканчивается каждое задание из очереди ScriptJobs. (Подробнее в статье c: Задания и очереди заданий .)
Я не уверен, какой вывод вы ожидали от своего кода, поскольку вы этого не делали ' Скажем так, но давайте рассмотрим более простой пример:
console.log("top");
new Promise(resolve => {
setTimeout(() => {
console.log("timer callback");
}, 0);
resolve();
})
.then(() => {
console.log("then callback 1");
})
.then(() => {
console.log("then callback 2");
});
console.log("bottom");
Вывод этого надежно:
top
bottom
then callback 1
then callback 2
timer callback
, поскольку:
- Задание ScriptJobs для запуска этого выполняется сценарий
console.log("top")
выполняется - запускается код функции исполнителя обещаний, который
- планирует задание таймера для «прямо сейчас», которое будет go в ScriptJobs очередь сразу или почти сразу
- Разрешает обещание (что означает, что обещание разрешено до того, как
then
вызвано к нему)
- Первые
then
перехватчики до первого обработчика выполнения, поставив в очередь задание PromiseJobs, потому что обещание уже выполнено - Второй
then
подключает второй обработчик выполнения (не ставит в очередь задание, ожидает обещание от первого then
) console.log("bottom")
выполняется - Текущее задание ScriptJob заканчивается
- Движок обрабатывает ожидающее задание PromiseJobs (первый обработчик выполнения)
- То выводит
"then callback 1"
и выполняет первый then
'sp romise (путем возврата) - Это ставит в очередь очередное задание в очереди PromiseJobs для обратного вызова во второй обработчик выполнения
- Поскольку очередь PromiseJobs не пуста, следующий PromiseJob подбирается и запускается
- Второй обработчик выполнения выводит
"then callback 2"
- PromsieJobs пуст, поэтому механизм подхватывает следующий ScriptJob
- Этот ScriptJob обрабатывает обратный вызов таймера и выводит
"timer callback"
В HTML spe c они используют несколько иную терминологию: «задача» (или «макрозадача») для заданий ScriptJobs и «микрозадача» для заданий PromiseJobs (и других аналогичных заданий).
Ключевым моментом является то, что: все PromiseJobs, поставленные в очередь во время ScriptJob, обрабатываются по завершении этого ScriptJob, включая любые PromiseJobs они очередь; только когда PromiseJobs пуст, следующий запуск ScriptJob выполняется.