Я изучал асинхронное поведение в JS, и по большей части все шло хорошо. Я понимаю синхронный способ выполнения кода, единый поток JS и то, как обратные вызовы, такие как внутри setTimeout, будут синхронизироваться API веб-браузера, а затем добавлены в очередь задач.
Цикл событий будет постоянно проверять стек вызовов, и только когда он пуст (весь код синхронизации выполнен), он будет принимать функции, которые были поставлены в очередь в очереди задач. Помещает их обратно в стек вызовов, и они выполняются.
Это довольно просто, и поэтому следующий код:
console.log('start');
setTimeout(() => console.log('timeout'), 0);
console.log('end');
Выведет start, end, timeout
.
Теперь, когда я начал читать об обещаниях, я понял, что они имеют более высокий приоритет, чем обычный асинхронный код, такой как тайм-аут, интервал, прослушиватель событий, и вместо этого будут помещены в очередь заданий / очередь микрозадач. Цикл событий сначала установит приоритет этой очереди и выполнит все задания до исчерпания, прежде чем перейти к очереди задач.
В этом все еще есть смысл, и в этом можно убедиться, запустив:
console.log('start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');
Это выводит start, end, promise, timeout
. Выполняется синхронный код, обратный вызов then
помещается в стек из очереди микрозадач и выполняется, задача обратного вызова setTimeout из очереди задач отправляется и выполняется. Пока все хорошо.
Я могу осмыслить приведенный выше пример, где обещание выполняется немедленно и синхронно, как сказано в официальной документации. То же самое произойдет, если мы создадим обещание с ключевым словом new и предоставим функцию исполнителя. Эта функция-исполнитель будет выполняться синхронно и разрешить функцию. Поэтому, когда встречается then, он может просто выполняться асинхронно на разрешенном обещании.
console.log('start');
const p1 = new Promise(resolve => {
console.log('promise 1 log');
resolve('promise 1');
});
p1.then(msg => console.log(msg));
console.log('end');
Приведенный выше фрагмент выведет start, promise 1 log, end, promise 1
, доказывающий, что исполнитель работает синхронно.
И здесь меня путают с обещаниями, допустим, у нас есть следующий код:
console.log('start');
const p1 = new Promise(resolve => {
console.log('promise 1 log');
setTimeout(() => {
resolve('promise 1');
}, 0);
});
p1.then(msg => console.log(msg));
console.log('end');
Это приведет к start, promise 1 log, end, promise 1
. Если функция-исполнитель запускается сразу, это означает, что setTimeout внутри нее будет помещен в очередь задач для последующего выполнения. Насколько я понимаю, это означает, что обещание еще не выполнено. Мы переходим к методу then
и обратному вызову внутри него. Это будет помещено в очередь заданий. остальная часть синхронного кода выполняется, и теперь у нас есть пустой стек вызовов.
Насколько я понимаю, обратный вызов обещания теперь будет иметь приоритет, но как он может выполняться с еще нерешенным обещанием? Обещание должно разрешиться только после выполнения внутри него setTimeout, который все еще находится в очереди задач. Я слышал, без каких-либо дополнительных разъяснений, что тогда он будет работать только в том случае, если обещание будет разрешено, и из моего вывода я вижу, что это правда, но я не понимаю, как это будет работать в этом случае. Единственное, о чем я могу думать, - это исключение или что-то подобное, и задача очереди задач получает приоритет перед микрозадачей.
Это оказалось длинным, так что я благодарен всем, кто нашел время, чтобы прочитать и ответить на это. Я хотел бы лучше понять очередь задач, очередь заданий и цикл событий, поэтому не стесняйтесь публиковать подробный ответ! Заранее спасибо.