从两个环境中下手:
浏览器
node环境
下面只讲解浏览器的事件循环
概念解析
在理解事件循环之前,先理解下面几个名词:
-
js是单线程语言
-
事件循环是js的一个执行机制
-
任务队列
js在执行的时候,当遇到异步事件时,并不会一直等待异步事件返回结果,而是将这个异步事件挂在执行栈不同的队列中,这个就是任务队列
-
执行栈
执行任务队列中的某个任务,这个被执行的任务称为执行栈
-
主线程
规定现在执行执行栈中的哪个事件
-
主线程循环
主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码
-
异步任务
- 微任务
- promise.then
- MutaionObserver
- process.nextTick
- 宏任务
- setTimeout
- setInterval
- UI渲染
- setImmediate
- I/O
- 微任务
浏览器中的事件循环
浏览器是多进程,多线程
浏览器在执行js的时候,会分为同步任务和异步任务,同步任务进入执行主线程,异步任务进入Event Table并注册函数(回调函数),注册成功滞后于会进入到Event Queue事件队列中,当主线程中的任务执行完毕时,会从任务队列中去读对应的函数进入到主线程中执行,这个过程是不断重复的,所以叫做事件循环
执行循序
- 先执行主线程
- 遇到宏队列,放到宏队列中
- 遇到微队列,放到微队列中
- 主线程执行完毕
- 执行微队列,微队列执行完毕
- 执行一次宏队列中的一个任务,执行完毕
- 执行微队列,执行完毕
- 依次循环
代码演示
console.log(1);
setTimeout(() => {
console.log(2);
process.nextTick(() => {
console.log(3);
});
new Promise((resolve) => {
console.log(4);
resolve();
}).then(() => {
console.log(5);
});
});
process.nextTick(() => {
console.log(6);
});
new Promise((resolve) => {
console.log(7);
resolve();
}).then(() => {
console.log(8);
});
setInterval(() => {
console.log(9);
process.nextTick(() => {
console.log(10);
});
new Promise((resolve) => {
console.log(11);
resolve();
}).then(() => {
console.log(12);
});
}, 5000);
// 顺序如下 => 1 7 6 8 2 4 3 5 9 11 10 12