Event loop的粗浅认识

事件轮询

js是单线程的。其事件轮询由:同步任务,异步任务,macrotask(宏任务),microtask (微任务)组成。其执行过程如下:

  • 同步任务: 主线程上的任务,前一个完成后后一个执行。
  • 异步任务:不进入主线程,进入任务队列(task queue)中执行,等于macrotask。
  • macrotask:任务队列的主体,同一个队列内的“先进先出”执行。不同的队列之间“先进后出”执行。
  • microtask :总在任务队列末尾执行,有新的microtask 继续加在末尾执行。

执行过程:1.同步任务执行 2. 任务按队列依次执行 3.微任务按队列依次执行 4.重复1-3

宏任务和微任务

对于宏任务微任务的概念的理解,一开始确实是不太清楚的。

先来说说宏任务,我们不妨这样来看,既然它是任务队列的主体,那么它一定由一个或者多个任务构成。抛开JS,[宏]这个字本身就不是单一的,在CS中的[宏]就是批量处理的意思。

对于稍微了解过一点点c的人来说,应该都不陌生,辟如:编译预处理命令,宏定义等等。

1
2
3
4
// 编译预处理命令
#include<stdio.h>
// 宏定义
#define PI 3.14

我将[编译预处理命令](在编译之前进行的处理)就看做是[宏任务],就是你写了一系列的前置操作,在后面的代码执行之前,这些宏任务全部需要执行完毕~

稍微生活化一点点,比如那个中国互联网起步的时候,我的同学之间,喜欢用QQ等级作为谈资。所以我让我的电脑开机后自动登录QQ;或者现今5G来临之前,男生多半玩过的MOBA类游戏,就拿LOL中的瞎子摸眼R闪这种操作,你完全可以选一个拥有宏命令的鼠标,设置测试后一键完成这种“用双手成就你的梦想”等秀的飞起的操作;还有诸如乔碧萝之类的人士,开启直播推流之前,对自己直播效果的优化。这些都是所谓宏任务

至于微任务,相信聪明可爱的你一定能够举一反一,找到自己对其充分的理解~:smile:

常见的宏任务和微任务:

宏任务

  • setTimeout
  • setInterval
  • setImmediate
  • requestAnimationFrame
  • I/O
  • UI rendering

微任务

  • process.nextTick
  • Promises
  • Object.observe
  • MutationObserver

执行图例

希望执行帧动画能让你对整个过程的理解清晰许多

小练习1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
console.log('script start');

setTimeout(function() {
console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});

console.log('script end');

// 浏览器输出顺序:
//script start
//script end
//promise1
//promise2
//setTimeout
小练习2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
  • await会将之后的代码抛入下一个执行队列,代码上的表现就是执行完await的会跳出函数体执行其他的同步任务。
  • setTimeout的回调函数会进入下一个同步任务队列中。
  • 如果输出顺序不一致,是因为各大浏览器对异步的处理是不一样的,没什么奇怪的。
  • 另外,node环境输出顺序也有很大差异。

评论