文章探讨一下两个个问题
什么是EventLoop?
解决什么问题?
js作为一门单线程网页脚本语言,诞生之初的作用便是操作dom。
由于是单线程语言,js一次只能执行一个任务,前面的任务执行完了才能执行下一个。这样一旦遇到大量任务或是遇到一个耗时的任务,网页就会出现假死,EventLoop正是为了解决这个问题。
托eventloop的福,js是非阻塞的。这是说当代码需要执行一项异步任务的时候,主线程会挂起这个任务,在异步任务返回结果的时候再根据一定规则去执行相应的回调。
重点1:事件队列(task queue)
js执行代码时,碰到异步事件,会将这个事件挂起,先执行其他任务。当一个异步事件返回结果后,js将其加入到与当前执行栈不同的另一个队列————事件队列。
重点2:何时执行
即便异步事件返回了结果,进入了事件队列,他也不会立即执行回调,而是等待当前执行栈中所有的任务执行完毕,主线程闲置才会去查看异步队列是否有任务,如果有,就取出这个队列第一位的事件,放入当前执行栈,开始执行其中的代码
重点3:如何执行
异步任务也是不相同的,分为宏任务(macro task)和(micro task)
- 宏任务
- setInterval()
- setTimeout()
- 微任务
- new Promise()
- new MutationObserver()
宏任务有宏任务的事件队列,微任务有微任务的事件队列,微任务优先执行,执行完毕才能执行下一个宏任务
总结
浏览器执行js代码时,先执行同步代码,中间碰到异步任务放到事件队列,如果是宏任务就放到宏任务队列,是微任务就放到微任务队列。同步代码执行完,当前执行栈为空,就去查看微任务队列,执行完毕后,取出第一位的宏任务执行。下一轮,继续同步事件——微任务——宏任务的执行方式。
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/