用一些例子做说明:
<script>
setTimeout(function () {
console.log("定时器开始啦");
});
new Promise(function (resolve) {
console.log("马上执行for循环");
for (var i = 0; i < 10000; i++) {
i == 5 && resolve();
// console.log(i);
}
console.log(i)
}).then(function () {
console.log("执行 then 函数啦");
});
console.log("代码执行结束");
</script>
<script>
let data = [];
$.ajax({
url: 'txt',
data: data,
success: () => {
console.log('发送成功');
}
});
console.log("代码执行结束");
/*
上述 Ajax 请求执行顺序:
ajax 进入 Event Table,注册回调函数 success;
执行 console.log('代码执行结束')。
ajax 事件完成,回调函数进入 Event Queue。
主线程从 Event Queue 读取回调函数 success 并执行。
*/
</script>
<script>
function task() {
console.log("回调函数");
}
function sleep(delay) {
while (delay) {
console.log(delay);
delay--;
}
}
setTimeout(() => {
task();
}, 3000);
sleep(1000000);
/*
上述 setTimeout 执行顺序
1、task() 进入Event Table 并注册,即时开始。
2、执行 sleep 函数,非常慢,计时仍在继续。
3、3秒到了,计时事件 timeout 完成,task() 进入Event Queue, 但是 sleep
也太慢了,还没执行完,只好等着。
4、sleep 终于执行完了,task() 终于从 Event Queue 进入了主线程执行。
*/
</script>
<script>
setTimeout(function() {
console.log("setTimeout");
});
new Promise(function (resolve) {
console.log("promise");
resolve();
}).then(function () {
console.log("then");
});
console.log("console");
/*
promise console then setTimeout
1、这段代码作为宏任务,进入主线程;
2、先遇到 setTimeout,那么将其回调函数注册后发到宏任务 Event Queue;
3、接下来遇到 Promise,new Promise 立即执行【打印 promise】,then 函数分发到微任务 Event Queue;
4、遇到 console.log(),立即执行【打印 console】;
5、到这里整体代码 scrip 作为第一个宏任务执行结束,看看有哪些微任务?发现 then 在微任务 Event Queue 里面,执行【打印 then】;
6、第一轮事件循环结束了,开始第二轮循环,当然从宏任务 Event Queue 开始。发现 Event Queue 中 setTimeout 对应回调函数,立即执行【打印 setTimeout】;
7、结束啦嘎
*/
</script>
<script>
console.log("1");
setTimeout(function () {
console.log("2");
process.nextTick(function () {
console.log("3");
});
new Promise(function (resolve) {
console.log("4");
resolve();
}).then(function () {
console.log("5");
});
});
process.nextTick(function () {
console.log("6");
});
new Promise(function (resolve) {
console.log("7");
resolve();
}).then(function () {
console.log("8");
});
setTimeout(function () {
console.log("9");
process.nextTick(function () {
console.log("10");
});
new Promise(function (resolve) {
console.log("11");
resolve();
}).then(function () {
console.log("12");
});
});
/*
第一轮循环流程
1、整体 script 作为第一个宏任务进入主线程,遇到 console.log, 【打印 1】;
2、遇到 setTimeout,其回调函数被分到宏任务 Event Queue 中,记为 setTimeout1;
3、遇到 process.nextTick(),其回调函数被分发到微任务 Event Queue中,记为 process1;
4、遇到 Promise, new Promise 直接执行,【打印 7】。then 被分发到微任务 Event Queue 中,记为 then1;
5、又遇到 setTimeout,其回调函数被分发到宏任务 Event Queue 中,记为 setTimeout2。
宏任务 Event Queue 微任务 Event Queue
setTimeout1 process1
setTimeout2 then1
上表是第一轮事件循环宏任务结束时各 Event Queue 的情况,此时已经输入 1、7;
6、发现 process1 和 then1 两个微任务,执行 process1 【打印 6】,执行 then1 【打印 8】;
7、好了,第一轮事件循环正式结束,这一轮的结果输出 1、7、6、8;
8、那么第二轮时间循环从 setTimeout1 宏任务开始,首先【打印 2】。接下来遇到 process.nextTick(),同样将其分发到微任务 Event Queue 中,记为 process2,
new Promise 立即执行,【打印 4】,then 也分发到微任务 Event Queue 中,记为 then2;
宏任务 Event Queue 微任务 Event Queue
setTimeout2 process2
then2
9、第二轮事件循环宏任务结束,发现微任务,执行 process2 【打印 3】,执行 then2 【打印 5】;
10、第二轮事件循环结束,第二轮输出 2、4、3、5;
11、第三轮事件循环开始,此时只剩 setTimeout2,执行,【打印 9】;
12、将 process.nextTick() 分发到微任务 Event Queue 中,记为 process3,
new Promise 立即执行,【打印 11】,then 也分发到 Event Queue 中,记为then3;
宏任务 Event Queue 微任务 Event Queue
process3
then3
13、第三轮事件循环宏任务执行结束,发现微任务,执行 process3 【打印 10】,执行 then3 【打印12】;
14、第三轮事件循环结束,第三轮输出 9、11、10、12
整段代码,共进行了三次事件循环,完整输出为 1、7、6、8、2、4、3、5、9、11、10、12
*/
</script>
感谢这位老哥:https://juejin.cn/post/6844903512845860872