每天做个总结吧,坚持就是胜利!
/**
@date 2021-05-28
@description 浏览器中的Event Loop
*/
复制代码
壹(序)
首先我们知道js是一门单线程且非阻塞的语言。
单线程是由于js主要的运行环境是浏览器,而浏览器中存在很多dom操作,假如js是一门多线程语言,那两个线程同时修改和删除同一个dom的时候,该怎么办?
非阻塞是js代码在执行过程中,遇到异步操作时,不会等待异步操作完成,而是将其挂起,等操作完成后执行相应的回调。而Event Loop
就用来实现js非阻塞特性。
贰(解释)
那么什么是Event Loop
呢?
一段js代码在执行过程中,同步代码会在主线程
中依次执行,遇到异步代码时会等待执行完成后(主线程继续往下执行同步代码),将相应的回调压入任务队列
中,等到主线程中的同步代码执行完成,会去任务队列中查看有没有需要执行的回调代码,有的话则执行,在这些回调中也是先执行同步代码,遇到异步代码则挂起,等待异步代码完成后压入任务队列
,同步执行完成后再去查看任务队列
中有没有需要执行的回调代码…这样一个循环过程,称为事件循环
。
看一段代码:
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
复制代码
首先同步执行代码console.log(1);
,输出1,然后遇到异步的setTimeout,然后往下执行同步代码console.log(3);
,输出3,同步代码执行完成后,去任务队列
中取出setTimeout
的回调执行,输出2;
叁(宏任务,微任务)
看下面一段代码:
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
const p = new Promise((resolve, reject) => {
resolve(4);
});
p.then(val => {
console.log(val)
});
console.log(3);
复制代码
按照刚刚的解释,应该是输出1,3,2,4
,但是实际上是输出1,3,4,2
;
这是因为任务还分为宏任务
,微任务
,执行的时候会首先执行完所有的微任务,再去执行宏任务;
宏任务:
- setInterval;
- setTimeout;
- setImmediate;
- I/O操作;
微任务:
- Promise;
- MutationObserver;
肆(练习)
做一道练习题:
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
; - 遇到
setTimeout
,压入任务队列
,且是一个宏任务; - 执行同步代码
async1();
输出async1 start
; - 遇到
await
,需先执行await
之后的函数async2
;输出async2
;其后代码压入任务队列
,且是一个微任务; - 执行Promise中的同步代码,输出
promise1
;resolve()
后的代码压入任务队列
,且是一个微任务; - 执行同步代码,输出
script end
; - 此次循环中的所有同步代码执行完成,开始执行
任务队列
中的回调,首先是第4步压入的微任务,输出async1 end
; - 继续执行第5步压入的微任务,输出
promise2
; - 执行完所有微任务,执行第2步压入的宏任务,输出
setTimeout
;
最终输出:script start
, async1 start
, async2
, promise1
, script end
, async1 end
, promise2
, setTimeout
。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END