console.log('1')
setTimeout(() => {
console.log('2')
}, 0)
function three() {
return new Promise(resolve => {
setTimeout(() => {
return new Promise(resolve => resolve('3'))
},0)
})
}
three().then(result => console.log(result))
console.log('4')
Этот фрагмент кода выводит 1 4 2
Это поведение, которое я ожидал, основываясь на моем понимании цикла обработки событий javascript и модели параллелизма. Но это оставляет меня с некоторыми затяжными вопросами.
Прежде чем перейти к этим вопросам, я сначала нарушу свое понимание этого фрагмента кода.
Почему код выводит 1
объяснение не требуется
Почему код выводит 4
обратный вызов, который выводит 2, загружается в очередь событий (она же очередь макрокоманд) через 0 мс, но не выполняется, пока не будет очищен основной стек вызовов.
, даже если three
было обещанием, которое было немедленно разрешено, его код загружается в очередь заданий (она же очередь микрозадач) и не будет выполняться, пока не будет очищен основной стек вызовов (независимо от содержимого). очереди событий)
Почему код выводит 2
после console.log(4)
основной стек вызовов пуст и javascript ищет следующий обратный вызов для загрузки в основной стек,Можно с уверенностью предположить, что в этот момент некоторые «рабочие потоки» уже поместили функцию обратного вызова, которая выводит 2, в очередь задач макроса. Это загружается в стек и выводится 2.
Почему код НЕ выводит 3
Это немного размыто для меня. Функция three
возвращает обещание, которое then
в главном потоке. Функции обратного вызова, пропущенные через then
, загружаются в очередь для микрозадач и выполняются перед следующей задачей в очереди для макрозадач. Таким образом, хотя вы можете подумать, что он будет запущен до обратного вызова, регистрирующего 2, на самом деле его вообще невозможно запустить. Это связано с тем, что Promise разрешается только с помощью функции обратного вызова его setTimeout, и эта функция обратного вызова (из-за setTimeout) будет работать только в том случае, если основной поток выполнения (тот же поток, который ожидает разрешения, обещает) пуст.
Почему это беспокоит меня
Я пытаюсь построить полную теоретическую мысленную модель того, как javascript управляет параллелизмом. Одна из недостающих частей в этой модели - это связь между сетевыми запросами, обещаниями и циклом событий. Возьмем приведенный выше фрагмент кода и предположим, что я заменил setTimeout three
на какой-то сетевой запрос (очень распространенная вещь в асинхронной веб-разработке). Предполагая, что сетевой запрос ведет себя аналогично setTimeout, в том случае, когда «рабочий поток» завершен, обратный вызов помещается в очередь задач макрокоманды, мне трудно понять, как этот обратный вызов даже выполняется. Но это то, что происходит буквально все время.
Может кто-нибудь помочь мне понять? Есть ли у меня пропущенные пробелы в моем текущем понимании параллелизма js? Я сделал неверное предположение? Имеет ли что-нибудь из этого смысл? лол