#javascript #asynchronous #ecmascript-6 #es6-promise #asynccallback
#javascript #асинхронный #ecmascript-6 #es6-обещание #asynccallback
Вопрос:
Я ожидаю, что этот код будет запущен, затем через 2 секунды стек выполнения станет пустым, и будет выполнен один обратный setTimeout
вызов . Я ожидаю этого, поскольку ожидаю, что очередь сообщений и очередь заданий будут пустыми (поскольку обещание еще не выполнено).
Итак, Callback
сначала печатается, затем через 3 секунды обещание разрешается, и его обратный вызов помещается в очередь заданий, и сообщение Promise is resolved
должно быть напечатано. Но это не то, что происходит. Итак, чего мне здесь не хватает?
Код:
setTimeout(function() {
console.log("Callbcack");
}, 0);
new Promise((resolve, reject) => {
console.log("Inside promise");
let ms = 5000 new Date().getTime();
while (new Date() < ms) {}
resolve("Promise is resolved");
}).then((data) => {console.log(data)})
.catch((err) => {
console.log(err);
})
var ms = 2000 new Date().getTime();
while (new Date() < ms) {}
Комментарии:
1. у вас есть цикл блокировки внутри обратного вызова вашего Promise, а другой — во внешней области. Это предотвращает обработку очереди сообщений.
2. циклы while не являются асинхронными, даже если вы помещаете их в обещание.
3. Была ли какая-то асинхронная операция (например, получение данных из БД) вместо цикла for в Promise, для обработки которого требуется некоторое время (скажем, 10 секунд).). Будет ли это иметь какое-либо значение в результатах?
Ответ №1:
Функция Promise executor запускается синхронно (точно во время вашего вызова new Promise(executor)
), поэтому обещание разрешается при выполнении кода верхнего уровня (в начальном стеке) через 5000 мс.
Затем выполняется очередь микрозадач, поэтому вы видите результат console.log(data)
.
Затем js (цикл событий) может свободно запускать следующую асинхронную часть, которая является обработчиком таймера.
Комментарии:
1. Была ли какая-то асинхронная операция (например, получение данных из БД) вместо цикла for в Promise, для обработки которого требуется некоторое время (скажем, 10 секунд).). Будет ли это иметь какое-либо значение в результатах?
2. @sv2311, если
resolve
он не был вызван в начальном стеке, но асинхронно через 10 секунд,console.log(data)
будет запущен последним. Вы можете проверить это, подделав вызов db сsetTimeout
помощью .
Ответ №2:
Вы только что обнаружили микрозадачи JavaScript. Короче говоря, на самом деле существует две разные очереди обратного вызова. Один для микрозадач и один для макрозадач. В вашем случае обратный вызов вашего Promise
является микрозадачей, в то время setTimeout
как обратный вызов является макрозадачей. Очередь микрозадач всегда обрабатывается перед очередью макрозадач.
Итак, даже если вы ставили в очередь function() { console.log("Callbcack"); }
раньше (data) => { console.log(data) }
, вторая всегда будет выполняться первой, независимо от того, как долго вы блокируете поток перед разрешением Promise
, потому что обе очереди будут обработаны, когда код верхнего уровня завершит выполнение.
Комментарии:
1. и ни один из них не будет обработан, если вы находитесь в середине временного
while
цикла…2. Да, это просто объясняет, почему
setTimeout
обратный вызов гарантированно выполняется послеPromise
обратного вызова, вопреки ожиданиям OP3. Эти асинхронные операции (setTimeout и выполнение обещания) обрабатываются веб-API или C / C API (если среда является Nodejs). Итак, я прав, говоря, что через 2 секунды глобальный контекст выполнения (верхний уровень) был удален из стека вызовов? Если это так, то через 2 секунды глобальный контекст был удален из стека вызовов, и теперь цикл событий просматривается в очереди сообщений и очереди микрозадач, в этот момент очередь микрозадач пуста, но в сообщении есть один обратный вызов (setTimeout),таким образом, цикл событий поместит его в стек вызовов и выполнит его.
4. Не совсем, потому что у вас также есть верхний уровень
Promise
.(resolve, reject) => {
Функция, переданная вPromise
конструкторе, выполняется синхронно (только.then((data) => {console.log(data)})
асинхронно), поэтому в вашем примере стек выполнения пуст через 7 секунд. На данный момент одна микрозадача и одна макрозадача поставлены в очередь, поэтому они выполняются в правильном порядке приоритета