js 彻底搞懂事件循环机制 Event Loop

我们都知道JavaScript是单线程语言,就是因为单线程的特性,就不得不提js中的同步和异步

一、同步和异步

所谓单线程,无非就是同步队列和异步队列,js代码是自上向下执行的,在主线程中立即执行的就是同步任务,比如简单的逻辑操作及函数,而异步任务不会立马立马执行,会挪步放到到异步队列中,比如ajax、promise、事件、计时器等等。

也就是先执行同步m 8 r _ 9 [,主线程结束后再按照异步的顺序再次执行。

二、时间循环(Event Loop)

Eve^ , Mnt Loop是什么w 1 Z T 7?中文翻译是事件循环,等待主. j $ j P L ) L b线程中任务全部完成后,- R G再回来把异步队列中任务放到主程序中运行,这样反复的循环,就是事件循环。

js 彻底搞懂事件循环机制 Event Loop

先来看组代U _ { ^ X )

console.log('开始111');
sr t D G ^ ! 2etTimeout(function() {
console.log('setTimeout111');o | l
},A M ^ t / 0);P = Y F o .
Prom2 | x 8 1 z } ] Pise.resolve(. D s 0).then(function() {
console.log('promise1h A H11');
}).then(functioJ j D Nn() {
console.logL ( ('promise222');
});
console.log('开始222');

我们猜想一下上面的代码,会怎样打印?我们知道,肯定是; ; G I先走同步的代码,从上往下,先打印 “开始111”,再打印“开始222”。
中途的三个异步,进入到了异步队列# i 9 C ^ A,等- Y #待同步执行完(打印完),返回来再执行异步,所以是后打印出来。
打印的_ b $ 0 b r y 3结果先放一放,我们稍后回来再说。现在我们中途插播一段知识点:

三、宏观任3 l 7 )务和微观任务(先执行微观任务,再执行宏观任务):

在事件循环中,每进行一次循环操作称为tick,tick 的任务处理模型是比较复杂的,里边有两个词:分别r K P j n y v是 Macro Task (宏任务)和 Mi3 ? 8 2 o h kcro Task(微任务)。

简单来说:

宏观任务主要k ` 9 E / B 6 g包含:setTl 7 # V G T 0 imeout、setIG N onterval、script(B 3 W f V s整体代码)、I/O、UI 交互事件、setImmediate(Node.js 环境)

微观任务主要包括:Promise、MutaionObserver、process.nextTick(Node.js 环境)

规范:先执行微观任务,再执行宏观任务

那么我们知道了,Promise 属于微观任务, setTimeo% B } & [ut、setInterval 属于宏$ Z Z } 1 x观任务,先执9 _ * K X , L 行微观任务,等微观l D r 9 G g j任务执行完,再执行宏观任务。所以我们再看一下这个代码:

console.log('开始111');

setTimeout(function() {
console.log('setTimeC ) L 5 [ H t F ;out111');
}, 0);

Promise.t . | 2 K 1 p }resolve().then(fuH ~ 4 @ ? + e nnctN P N Mion() {
console.log('promise111');
}).then(fZ - +unction() {
c$ ~ Console.log('promise222');
});

console.log('开始222');

我们按照步骤来分析下:

1、遇到同步任务,直接先打印 “开始111”。
2+ _ x h b t x、遇到异步 setTimeout ,先放到队列中等待执行。
3、遇到了 Promise ,放到等待队列中。
4、遇到同步任务,直接打印 “开始U B k _ L #222”。
5、同步q } C E . _ v m =执行完,返回执行队列中的代码,从上往下执行,发现有宏观9 = f F _ E ]任务 setTimeout 和微观任务 Promise ,那么先执行微观任务,再执行宏观任务。

所以打印的顺序为: 开始111 、开始222 、 promE C l [ % ] ; Vise111 、 promise222 、 setTimeout111 。

同理,我们再^ M ] _ / f来分析一个代码:

console.log('开始111');

setTimeoutR / | & # 9(function () {
console.Z 6 ^log('timeo9 M o # ; lut111');
});

new Promise(resolve => {
console.log('promise111');
resolve();
setTimeout(() => console.log('ti7 % } T q G q o =meout222'));
}).then(function () {
console.log('promise222')
})

console.log(s q G _ Q'开始222');

分析一下:

1、遇到同# V [步代码,先打印 “开始111” 。
2、遇到w 1 9 v o M A ?setTimeout异步,放入队列,等待执行 。
3、中途遇到Promise函数,函数直接执行9 6 ^ X Y,打印 “$ U promise111”。
4、遇到setTimeout ,属于异~ e [ c步,放入队列,等待执行。
5、遇到Promise的thenl d W等待成功返回,异步,t C _ G放入队- Z S ! c L } k列。
6、遇到同步,打印 “开始222”。
7、执行完,返回,将异步队列中的代码,按顺序执行。有一个微观任务,tZ $hen后的,所f Y D } m x @以打印 “promise222”,再执行两个宏观任务 “timeout111” “timeout222”。

所以,打印的顺序为:开始111 、 promise111 、 w ) o r : p K ? 开始222 、 promise222 、 timeout111 、 timeout222 .

先执行主任务,把异步任务放入循环队列当中,等待主任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,# - :再执行c o P + J p ^ = G宏观任务。一直这样循环,反复执行,就{ & R l I { C是事件循环机制。

来自:https://www.cnblogs.com/tangjianqiang/p/13470363.html

站长推荐

1.云服务推荐: 国内{ @ k 主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/9574