Эта статья участвовала в "Проект «Звезда раскопок»”, чтобы выиграть творческий подарочный пакет и бросить вызов творческим поощрительным деньгам.
предисловие
Всем привет, меня зовут Линь Сансинь, оEventLoop
Очков знаний в тесте в обычное время много, но они также тесно связаны с нашей повседневной работой.EventLoop
Порядок выполнения может очень помочь нам найти проблему. На самом деле нормальноEventLoop
Порядок легко сказать, но еслиsetTimeout + Promise + async/await
Объединить усилия очень сложно. Сегодня я возьму тебя过五关斩六将
, победить их! ! !
Примечание. В этой статье не рассматривается механизм выполнения Nodejs.
Синхронный Асинхронный
Что такое асинхронный и что синхронный, много говорить не буду, расскажу через небольшую историю.
-
同步
: Вы звоните в книжный магазин, чтобы заказать книги, начальник говорит я проверю, вы не вешаете трубку и ждете, начальник скажет вам результаты, вы не можете заниматься своими делами в этот период -
异步
: Ты звонишь в книжный магазин, чтобы заказать книги, начальник сказал, я посмотрю, я тебе потом скажу, ты кладешь трубку и иди сначала занимайся своими делами.
Механизм выполнения JS
На самом деле это не сложно, механизм выполнения кода JavaScript, я сведу его к трем предложениям
- 1. встреча
同步代码
прямое исполнение - 2. встреча
异步代码
отложи это и положи его回调函数
сохранить его, сохранить его事件队列
- 3. Ждать всех
同步代码
все выполняются, а затем из事件队列
все хранится в异步回调函数
Выньте его и выполните по порядку
См. пример ниже
console.log(1) // 同步
setTimeout(() => {
console.log(2) // 异步
}, 2000);
console.log(3) // 同步
setTimeout(() => {
console.log(4) // 异步
}, 0);
console.log(5) // 同步
输出 : 1 3 5 4 2
Макрозадачи и микрозадачи
Как упоминалось ранее, после выполнения всего кода синхронизации начните с事件队列
выполнять все подряд异步回调函数
.
фактически事件队列
Это тоже небольшая группа, а у других свои правила, это похоже на школу, которая управляет многими клубами, и у их собственных клубов тоже свои правила.
Опять же, почему事件队列
Вам нужны свои правила? В противном случае, вы должны сначала подумать, почему клубы в школе имеют свои правила и оценки.Это потому, что у одних людей сильные способности, а у других слабые, поэтому есть уровни уровней. фактически事件队列
тоже самое,事件队列
Он используется для хранения асинхронных обратных вызовов, но асинхронные также делятся на типы.Асинхронные задачи делятся на宏任务
а также微任务
,а такжеМикрозадачи выполняются раньше макрозадач
Что такое макрозадачи и микрозадачи?
задача макроса
# | браузер | Node |
---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
микрозадачи
# | браузер | Node |
---|---|---|
Promise.prototype.then catch finally | ✅ | ✅ |
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |
Процесс реализации
Итак, давайте поговорим об общем процессе выполнения.
пример
Вы можете следовать моим шагам по решению проблем, в основном 90% проблем не вызывают стресса! ! !
- 1. Маркировка различия между асинхронным и синхронным
- 2. В асинхронности маркеры различают макрозадачи и микрозадачи
- 3. Количество раундов, медленно идите круг за кругом
console.log(1) // 同步
setTimeout(() => {
console.log(2) // 异步:宏任务
});
console.log(3) // 同步
Promise.resolve().then(()=>{ // 异步:微任务
console.log(4)
})
console.log(5) // 同步
первый раунд
- Описание: сначала выведите синхронное выполнение
- Выход: 1, 3, 5
- Создайте задачу макроса:
setTimeout
, который производит микрозадачи:Promise.prototype.then
второй раунд
- Описание: микрозадачи выполняются в первую очередь
- выход: 4
- Макрозадача создания: нет, микрозадача создания: нет
- Оставшиеся задачи макроса:
setTimeout
, остальные микрозадачи: нет
Третий тур (конец)
- Описание: выполнить задачу макроса
- выход: 2
- Макрозадача создания: нет, микрозадача создания: нет
- Оставшиеся макрозадачи: нет, оставшиеся микрозадачи: нет
первый раунд
Подумайте об идее решения проблемы, которую я только что упомянул. Вы можете следовать этой идее. Эта проблема — вопрос нескольких минут.
console.log(1)
setTimeout(() => {
console.log(2)
Promise.resolve().then(() => {
console.log(3)
})
});
console.log(4)
new Promise((resolve,reject) => {
console.log(5)
resolve()
}).then(() => {
console.log(6)
setTimeout(() => {
console.log(7)
})
})
console.log(8)
Шаг 1: Марк
Примечание: обещания
executor
Это синхронно! ! !
console.log(1) // 同步
setTimeout(() => {
console.log(2) // 异步:宏任务 setTimeout1
Promise.resolve().then(() => { // 异步:微任务 then1
console.log(3)
})
});
console.log(4) // 同步
new Promise((resolve,reject) => {
console.log(5) // 同步
resolve()
}).then(() => { // 异步:微任务 then2
console.log(6)
setTimeout(() => {
console.log(7) // 异步:宏任务 setTimeout2
})
})
console.log(8) // 同步
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить вывод внешней синхронизации | 1, 4, 5, 8 | Задача макроса:setTimeout1 Микрозадачи: then2
|
Задача макроса:setTimeout1 Микрозадачи: then2
|
второй раунд | Выполнение микрозадачthen2
|
6 | Задача макроса:setTimeout2 Микрозадачи: нет |
Задача макроса:setTimeout1,setTimeout2 Микрозадачи: нет |
третий раунд | Выполнять задачи макросаsetTimeout1
|
2 | Задача макроса: нет Микрозадачи: then1
|
Задача макроса:setTimeout2 Микрозадачи: then1
|
четвертый раунд | Выполнение микрозадачthen1
|
3 | Задача макроса: нет Микрозадачи: нет |
Задача макроса:setTimeout2 Микрозадачи: нет |
пятый раунд | Выполнять задачи макросаsetTimeout2
|
7 | Задача макроса: нет Микрозадачи: нет |
Задача макроса: нет Микрозадачи: нет |
Второе препятствие
все встречаютсяPromise.then.then
В это время, если вы немного запутались, вы можете переключить его, и мы поговорим об этом ниже.
Уведомление:
then
метод автоматически вернет новыйPromise
, то есть,return new Promise
,специфическийPromise源码
Каждый может видеть меня этой статьей.После прочтения принцип написания промиса от руки, самая понятная версия[Чтение: 1,1 Вт, лайков: 430]
setTimeout(() => {
console.log(1)
}, 0)
console.log(2)
const p = new Promise((resolve) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
}).then(() => {
console.log(5)
})
console.log(6)
Шаг 1: Отметить + Преобразовать
Примечание. Преобразование здесь только для вопроса, его легче понять, обычно не делайте этого преобразования, обычно это преобразование не подходит, это неправильно.
setTimeout(() => { // 异步:宏任务 setTimeout
console.log(1)
}, 0)
console.log(2) // 同步
const p = new Promise((resolve) => { // p 是 then1 执行返回的新 Promise
console.log(3) // 同步
resolve()
}).then(() => { // 异步:微任务 then1
console.log(4)
// 拿着 p 重新 then
p.then(() => { // 异步:微任务 then2
console.log(5)
})
})
console.log(6) // 同步 6
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить синхронный вывод | 2, 3, 6 | Задача макроса:setTimeout Микрозадачи: then1
|
Задача макроса:setTimeout Микрозадачи: then1
|
второй раунд | Выполнение микрозадачthen1
|
4 | Задача макроса: нет Микрозадачи: then2
|
Задача макроса:setTimeout Микрозадачи: then2
|
третий раунд | Выполнение микрозадачthen2
|
5 | Задача макроса: нет Микрозадачи: нет |
Задача макроса:setTimeout Микрозадачи: нет |
четвертый раунд | Выполнять задачи макросаsetTimeout
|
1 | Задача макроса: нет Микрозадачи: нет |
Задача макроса: нет Микрозадачи: нет |
Третий уровень
Скажи еще раз: все сталкиваютсяPromise.then.then
В это время, если вы немного запутались, вы можете изменить его
Уведомление:
then
метод автоматически вернет новыйPromise
, то есть,return new Promise
,специфическийPromise源码
, вы можете увидеть мою статьюПосле прочтения принцип написания промиса от руки, самая понятная версия[Чтение: 1,1 Вт, лайков: 430]
new Promise((resolve,reject)=>{
console.log(1)
resolve()
}).then(()=>{
console.log(2)
new Promise((resolve,reject)=>{
console.log(3)
resolve()
}).then(()=>{
console.log(4)
}).then(()=>{
console.log(5)
})
}).then(()=>{
console.log(6)
})
Шаг 1: Отметить + Преобразовать
Примечание. Преобразование здесь только для вопроса, его легче понять, обычно не делайте этого преобразования, обычно это преобразование не подходит, это неправильно.
const p1 = new Promise((resolve, reject) => { // p1 是 then1 执行返回的新 Promise
console.log(1) // 同步
resolve()
}).then(() => { // 异步:微任务 then1
console.log(2)
const p2 = new Promise((resolve, reject) => { // p2 是 then2 执行返回的新 Promise
console.log(3) // then1 里的 同步
resolve()
}).then(() => { // 异步:微任务 then2
console.log(4)
// 拿着 p2 重新 then
p2.then(() => { // 异步:微任务 then3
console.log(5)
})
})
// 拿着 p1 重新 then
p1.then(() => { // 异步:微任务 then4
console.log(6)
})
})
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить вывод внешней синхронизации | 1 | Задача макроса: нет Микрозадачи: then1
|
Задача макроса: нет Микрозадачи: then1
|
второй раунд | Выполнение микрозадачthen1
|
2, 3 | Задача макроса: нет Микрозадачи: then2、then4
|
Задача макроса: нет Микрозадачи: then2、then4
|
третий раунд | Выполнение микрозадачthen2,then4
|
4, 6 | Задача макроса: нет Микрозадачи: then3
|
Задача макроса: нет Микрозадачи: then3
|
четвертый раунд | Выполнение микрозадачthen3
|
5 | Задача макроса: нет Микрозадачи: нет |
Задача макроса: нет Микрозадачи: нет |
Четвертый проход
Этот на один больше предыдущегоreturn
Я сказал раньше,then
метод автоматически вернет новыйPromise
, эквивалентноreturn new Promise
, а если вручную написатьreturn Promise
,Этоreturn
это вы вручную написали этоPromise
new Promise((resolve, reject) => {
console.log(1)
resolve()
}).then(() => {
console.log(2)
// 多了个return
return new Promise((resolve, reject) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
}).then(() => { // 相当于return了这个then的执行返回Promise
console.log(5)
})
}).then(() => {
console.log(6)
})
Шаг 1: Отметить + Преобразовать
из-заreturn
даthen3
выполнение возвращаетPromise
,такthen4
Фактическиthen3Promise.then()
, поэтому его можно преобразовать вthen3.then4
new Promise((resolve, reject) => {
console.log(1) // 同步
resolve()
}).then(() => { // 异步:微任务 then1
console.log(2) // then1 中的 同步
new Promise((resolve, reject) => {
console.log(3) // then1 中的 同步
resolve()
}).then(() => { // 异步:微任务 then2
console.log(4)
}).then(() => { // 异步:微任务 then3
console.log(5)
}).then(() => { // 异步:微任务 then4
console.log(6)
})
})
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить вывод внешней синхронизации | 1 | Задача макроса: нет Микрозадачи: then1
|
Задача макроса: нет Микрозадачи: then1
|
второй раунд | Выполнение микрозадачthen1
|
2, 3 | Задача макроса: нет Микрозадачи: then2、then3、then4
|
Задача макроса: нет Микрозадачи: then2、then3、then4
|
третий раунд | Выполнение микрозадачthen2、then3、then4
|
4, 5, 6 | Задача макроса: нет Микрозадачи: нет |
Задача макроса: нет Микрозадачи: нет |
Уровень 5
new Promise((resolve, reject) => {
console.log(1)
resolve()
}).then(() => {
console.log(2)
new Promise((resolve, reject) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
}).then(() => {
console.log(5)
})
}).then(() => {
console.log(6)
})
new Promise((resolve, reject) => {
console.log(7)
resolve()
}).then(() => {
console.log(8)
})
Шаг 1: Отметить + Преобразовать
const p1 = new Promise((resolve, reject) => { // p1 是 then1 执行返回的新 Promise
console.log(1) // 同步
resolve()
}).then(() => { // 异步:微任务 then1
console.log(2)
const p2 = new Promise((resolve, reject) => { // p2 是 then2 执行返回的新 Promise
console.log(3) // then1 里的 同步
resolve()
}).then(() => { // 异步:微任务 then2
console.log(4)
// 拿着 p2 重新 then
p2.then(() => { // 异步:微任务 then3
console.log(5)
})
})
// 拿着 p1 重新 then
p1.then(() => { // 异步:微任务 then4
console.log(6)
})
})
new Promise((resolve, reject) => {
console.log(7) // 同步
resolve()
}).then(() => { // 异步:微任务 then5
console.log(8)
})
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить вывод внешней синхронизации | 1, 7 | Задача макроса: нет Микрозадачи: then1、then5
|
Задача макроса: нет Микрозадачи: then1、then5
|
второй раунд | Выполнение микрозадачthen1、then5
|
2, 3, 8 | Задача макроса: нет Микрозадачи: then2、then4
|
Задача макроса: нет Микрозадачи: then2、then4
|
третий раунд | Выполнение микрозадачthen2、then4
|
4, 6 | Задача макроса: нет Микрозадачи: then3
|
Задача макроса: нет Микрозадачи: then3
|
четвертый раунд | Выполнение микрозадачthen3
|
5 | Задача макроса: нет Микрозадачи: нет |
Задача макроса: нет Микрозадачи: нет |
Уровень 6
фактическиasync/await
Принцип внутренней реализации зависит отPromise.prototype.then
Постоянная вложенность, ее также можно преобразовать в заголовок, о чем будет сказано ниже.
Заинтересованные друзья могут прочитать мою статью7 картинок, принцип async/await, которые можно сделать за 20 минут! Зачем так долго[Объем чтения: 1,8 Вт, лайков: 571]
async function async1() {
console.log(1);
await async2();
console.log(2);
}
async function async2() {
console.log(3);
}
console.log(4);
setTimeout(function () {
console.log(5);
});
async1()
new Promise(function (resolve, reject) {
console.log(6);
resolve();
}).then(function () {
console.log(7);
});
console.log(8);
Шаг 1: Отметить + Преобразовать
Примечание. Преобразование здесь только для вопроса, его легче понять, обычно не делайте этого преобразования, обычно это преобразование не подходит.
console.log(4); // 同步
setTimeout(function () {
console.log(5); // 异步:宏任务 setTimeout
});
// async1函数可转换成
console.log(1) // 同步
new Promise((resolve, reject) => {
console.log(3) // 同步
resolve()
}).then(() => { // 异步:微任务 then1
console.log(2)
})
// async1函数结束
new Promise(function (resolve, reject) {
console.log(6); // 同步
resolve();
}).then(function () { // 异步:微任务 then2
console.log(7);
});
console.log(8); // 同步
Шаг 2: Разделите раунды
количество раундов | иллюстрировать | выход | производить | остальной |
---|---|---|---|---|
первый раунд | Выполнить синхронный вывод | 4, 1, 3, 6, 8 | Задача макроса:setTimeout Микрозадачи: then1、then2
|
Задача макроса:setTimeout Микрозадачи: then1、then2
|
второй раунд | Выполнение микрозадачthen1、then2
|
2, 7 | Задача макроса: нет Микрозадачи: нет |
Задача макроса:setTimeout Микрозадачи: нет |
третий раунд | Выполнять задачи макросаsetTimeout
|
5 | Задача макроса: нет Микрозадачи: then5
|
Задача макроса: нет Микрозадачи: нет |
домашнее задание после уроков
Напоследок дам вам две операции, которые помогут закрепить полученные знания из статьи, вы можете присоединиться к моей группе рыбалки в мутной воде, быть答案
обсуждение. Чтобы присоединиться к группе нажмите здесьв группу, было почти1000人
Присоединяйтесь к исследованию, буду проводить его регулярно学习分享,模拟面试
Ждите обучающих мероприятий, учитесь вместе и прогрессируйте вместе! ! !
Вопрос 1 (вопрос для размышления)
Подумайте о следующих двух, в чем разница?
// 第一种
const p = new Promise((resolve, reject) => {
resolve()
}).then(() => console.log(1)).then(() => console.log(2))
// 第二种
const p = new Promise((resolve, reject) => {
resolve()
})
p.then(() => console.log(1))
p.then(() => console.log(2))
Вопрос 2 (без проблем)
async function async1() {
console.log(1);
await async2();
console.log(2);
}
async function async2() {
console.log(3);
}
new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(4)
}, 1000);
}).then(() => {
console.log(5)
new Promise((resolve, reject) => {
setTimeout(() => {
async1()
resolve()
console.log(6)
}, 1000)
}).then(() => {
console.log(7)
}).then(() => {
console.log(8)
})
}).then(() => {
console.log(9)
})
new Promise((resolve, reject) => {
console.log(10)
setTimeout(() => {
resolve()
console.log(11)
}, 3000);
}).then(() => {
console.log(12)
})
Вопрос 3 (несколько сложный)
Этот вопрос может一分钟内
Найдите меня, чтобы получить награду. Этот вопрос должен иметь определенные требования.Promise原理基础 + async/await原理基础
Легче ответить правильно.Заинтересованные студенты могут прочитать статьи, которые я написал ранее.
- После прочтения принцип написания промиса от руки, самая понятная версия[Чтение: 1,1 Вт, лайков: 430]
- 7 картинок, принцип async/await, которые можно сделать за 20 минут! Зачем так долго[Объем чтения: 1,8 Вт, лайков: 571]
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async start')
return new Promise((resolve, reject) => {
resolve()
console.log('async2 promise')
})
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0);
async1()
new Promise((resolve) => {
console.log('promise1')
resolve()
}).then(() => {
console.log('promise2')
}).then(() => {
console.log('promise3')
})
console.log('script end')
Эпилог
Если вы считаете, что эта статья вам немного поможет, поставьте лайк и поддержите Линь Сансиня, ха-ха. Или присоединяйтесь к моей группе, ха-ха, давайте ловить рыбу и учиться вместе: meron857287645