前言
众所周知,JavaScript是一门单线程脚本语言,即同一时间只能做一件事。由于网络请求、用户交互、UI渲染等操作会阻塞主线程,所以就诞生了事件循环(Event Loop)的解决方案。
js单线程的原因
当多个操作DOM的线程任务同时进行时,浏览器无法判断其优先级。
异步执行机制
- 在主线程的执行栈中执行所有的同步任务
- 异步任务执行完毕后,会在任务队列中分发一个事件
- 当执行栈中所有的同步任务执行完毕后,检查任务队列中有没有需要执行的异步任务事件,将事件取出放到主线程的执行栈中执行。
- 重复步骤3
异步任务中的宏任务与微任务
宏任务:srcipt整体代码、setTimeout定时器、setInterval、UI渲染、I/O操作等 微任务:promise.then()、MutaionObserver()、process.nextTick()
事件循环
在js中事件循环是指在浏览器或者node.js运行时环境中负责管理执行顺序的机制。 在了解了异步执行机制以后,串联起宏任务与微任务,帮助我们更好的理解事件循环。在事件循环中,每一次循环可以理解为一个task,每一个task过程为:
- 执行先进入执行栈的宏任务(通常指的是srcipt整体代码)
- 检查是否存在微任务,如果存在则执行微任务,直至微任务队列清空
- 更新render渲染函数(每次事件循环的执行都可能影响页面重新渲染)
- 重复以上步骤(开始执行新的宏任务)
大致顺序为宏→微→宏
练习
(这里引用其他博主的练习题,自己能学会能理解就行)
console.log("1");
//setTimeout1
setTimeout(function () {
console.log("2");
new Promise(function (resolve) {
console.log("3");
resolve();
}).then(function () {
console.log("4");
});
//setTimeout2
setTimeout(function () {
console.log("5");
new Promise(function (resolve) {
console.log("6");
resolve();
}).then(function () {
console.log("7");
});
});
console.log("14");
});
new Promise(function (resolve) {
console.log("8");
resolve();
}).then(function () {
console.log("9");
});
//setTimeout3
setTimeout(function () {
console.log("10");
new Promise(function (resolve) {
console.log("11");
resolve();
}).then(function () {
console.log("12");
});
});
console.log("13");
解析:首先执行同步代码,此时打印1 8 13,promise.then()为微任务,执行栈中执行同步任务后,执行微任务此时打印9。此时所有微任务执行完毕,开始下一轮宏任务,目前宏任务队列中为setTimeout1和setTimeout3,首先执行setTimeout1,先打印2 3 14,此时又遇到promise.then(),即后执行4,执行setTimeout1时发现还存在宏任务,添加到宏任务队列中(setTimeout3之后),开始下一轮宏任务,目前宏任务队列中为setTimeout3和setTimeout2,区分好setTimeout3和setTimeout2的顺序后,后续打印顺序就好理解了,这里就不一一叙述了。总体打印顺序为1 8 13 9 2 3 14 4 10 11 12 5 6 7。
总结
之前对这些前端中常用的知识点理解的很浅,接下来边加深理解边更新一些相关知识。如有错误请各位多批评指正。