Почему отображается финиш перед тем, как остальные обещания остаются для выполнения.
Поскольку в этом коде ничего не говорит о том, что console.log
ожидает выполнения обещаний перед выполнением.Если вы хотите это сделать, соберите их в массив, а затем используйте:
Promise.all(theArray)
.then(() => {
console.log("finish");
});
..., чтобы сказать, что они должны ждать их всех.
Помните, что обработчики then
всегда вызывается асинхронно.Таким образом, ваш код создает три цепочки обещаний, затем выводит console.log
в конце, а затем получает асинхронные обратные вызовы для обработчиков then
- так что эти результаты отображаются позже.
Примечание:Код в вашем вопросе может быть написан более просто так:
for(let i = 0; i < 3; i++) {
console.log("i = " + i);
Promise.resolve(i)
.then(r => {
console.log("promise 1 of " + r);
return r;
})
.then(r => {
console.log("promise 2 of " + r);
return r;
});
}
console.log("finish");
Почему:
- Функция исполнителя обещания (функция, которую вы передаетеконструктор) выполняется синхронно, поэтому нет никакой разницы между строкой
console.log("i = " + i);
в качестве первой строки функции-исполнителя или чуть выше строки, в которой вы создаете обещание. Promise.resolve
создает разрешенноеобещание с указанным вами значением. then
всегда создает новое обещание.Когда вы возвращаете значение не обещания из обработчика then
, это значение является значением разрешения обещания, возвращаемого then
.Если вы вернете обещание, то созданное обещание then
будет «подчинено» обещанию, которое вы вернете (ожидает его разрешения или отклонения, а затем делает то же самое).
В комментарии вы задали очень умный вопрос:
Если «затем» вызывается асинхронно, то порядок вывода этих обещаний может быть не предсказан, верно?
Незначительный момент: then
не вызывается асинхронно, его обработчик (функция, которую вы передаете его) вызывается асинхронно.
В общем случае, да, верно, вы можете 'Предсказать порядок независимых обещаний (которые не связаны друг с другом).Вы можете предсказать обещания, что связаны вместе (более ранние в цепочке обрабатываются раньше, чем более поздние).В вашем коде у вас есть три независимых цепочки (одна для i = 0, одна для i = 1 и другая для i = 2);к каждой цепочке прикреплены два обработчика («1 из» и «2 из»).Итак, вы знаете, что «1 из» в цепочке «i = 0» произойдет раньше, чем «2 из» в той же цепочке, но в общем случае вы не знаете, будет ли i = 0
единица первым или i = 2
один или что-то еще.
Но , в данном конкретном случае порядок можно предсказать (по крайней мере, в браузерах, а также в Node.js), поскольку начальныйОбещание в каждой цепочке начинается предварительно разрешенным, что означает, что вызов его обработчика then
помещается в очередь для микрозадач сразу после вызова then
.Очередь для микрозадачи запускается в конце каждой задачи (она же называется «макрозадача»).Таким образом, задача, выполняющая ваш основной код, немедленно ставит обратный вызов в очередь на обработчик «1 из» каждой цепочки.Когда этот обработчик запускается, он ставит в очередь микрозадачу для вызова обработчика «2 of».Таким образом, поскольку обещания начинают решаться, мы знаем, что получим результат, который вы получите.Но в общем случае вы правы, вы не можете предсказать между цепями.
¹ Это веб-термин для этого;спецификация JS называет это очередью PromiseJobs.Подробнее о "микрозадачах" и задачах / макрозадачах в этот ответ .