本人一开始对于JS的执行机制了解很模糊,通过查找好多大牛资料总结了一下,终于理解通透了,希望我的文章能帮助到你哟,阅读期间有各种疑问欢迎@我,咱们一起探讨成长☺️!
事件循环
JS是单线程执行的,JS执行时基于一种事件循环的机制,形成了基本没有阻塞(除了alert或同步XHR等操作)的状态。
JS的运行环境主要有浏览器,Node。根据JS在浏览器中运行规范,每个线程都有事件循环(Event Loop)。
JS在执行任务时,所有任务可以分为两种 ,一种是同步任务,另一种是异步任务。 同步任务指在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程,而进入‘任务队列’的任务,只有‘任务队列’通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
任务有同步任务,异步任务。而异步任务又分为宏任务和微任务
简单的说:js执行任务的顺序 主线程--微任务--渲染--宏任务。此过程会不断重复,这个过程就叫事件循环)
常见异步任务类型
settimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行
promise本身是同步的立即执行函数(同步)
promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行;
async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把await表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
宏任务和微任务
宏任务(macro-task)
可以理解成:每次执行栈的代码就是一个宏任务(包括每次从事件队列中获取的一个事件回调并放到执行中执行)。
浏览器为了能够使得 JS 内部 macro-task 与 DOM 任务有序地执行,会在宏任务执行结束之后,在下一个宏任务开始执行之前,对页面进行重新渲染。
macro-task -> render -> macro-task -> ...
宏任务包括:
script全部代码
setInterval
setTimeout
setImmediate(node.js)
XHR 回调
事件回调(鼠标键盘事件)
indexedDB 数据库等 I/O 操作
UI rendering
微任务(micro-task)
可以理解成:当前 macro-task执行结束之后立即执行的任务。(在下一个 macro-task 之前 ,在渲染之前)
macro-task -> micro-task -> render -> macro-task -> ...
微任务包括:
Promise.then catch finally
async, await
process.nextTick(node.js)
MutationObserver
Object.observe(已被弃用)
宏任务与微任务执行顺序:
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务队列是否为空,如果为空的话,就执行宏任务,否则就一次性执行完所有微任务。
每次单个宏任务执行完毕后,检查微任务队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务后,设置微任务队列为null,然后再执行宏任务,如此循环。
总结:同步—>微任务—>宏任务
例子
console.log('ok')
new Promise(function(resolve){
console.log('1');
resolve();
}).then(function(){
console.log('2')
});
setTimeout(function(){
console.log('3')
});
console.log('4');
//ok,1,4,2,3
console.log(1)
process.nextTick(() => { // 微任务
console.log(8)
setTimeout(() => {
console.log(9)
})
})
setTimeout(() => { // 宏任务
console.log(2)
new Promise(() => {
console.log(11)
})
})
// 特殊说明: new Promise()属于主线程任务
let promise = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(10)
})
resolve()
// 这个console也属于主线程任务
console.log(4)
})
fn()
console.log(3)
promise.then(() => { //微任务
console.log(12)
})
function fn(){
console.log(6)
}
结果是1、4、6、3、12、8、2、11、10、9