Каким должен быть результат этой программы Javascript, имеющей асинхронные операции?

#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 обратного вызова, вопреки ожиданиям OP

3. Эти асинхронные операции (setTimeout и выполнение обещания) обрабатываются веб-API или C / C API (если среда является Nodejs). Итак, я прав, говоря, что через 2 секунды глобальный контекст выполнения (верхний уровень) был удален из стека вызовов? Если это так, то через 2 секунды глобальный контекст был удален из стека вызовов, и теперь цикл событий просматривается в очереди сообщений и очереди микрозадач, в этот момент очередь микрозадач пуста, но в сообщении есть один обратный вызов (setTimeout),таким образом, цикл событий поместит его в стек вызовов и выполнит его.

4. Не совсем, потому что у вас также есть верхний уровень Promise . (resolve, reject) => { Функция, переданная в Promise конструкторе, выполняется синхронно (только .then((data) => {console.log(data)}) асинхронно), поэтому в вашем примере стек выполнения пуст через 7 секунд. На данный момент одна микрозадача и одна макрозадача поставлены в очередь, поэтому они выполняются в правильном порядке приоритета