<>什么是事件循环(Event Loop)?

众所周知, Javascript是一门单线程的语言, 单线程即同一时间只能做一件事, 但这并不意味着JavaScript
在执行代码的过程中就会一直阻塞,而解决单线程不阻塞的这个机制就叫做事件循环(Event Loop), 也就是同步和异步的概念.

<>任务执行流程

在JS中, 所有的任务都可以分为了同步任务和异步任务

*
同步任务: 立即执行的任务, 且只有上一个同步任务执行完毕, 才会执行下一个任务

同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。

*
异步任务: 即在任务执行时不能立刻得到结果, 而是需要在将来通过一定的手段获取, 则称之为异步任务, 例如网络请求, 定时器, 计时器等

异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作。

同步任务与异步任务的运行流程图如下:

从上图可以看到, 同步任务和异步任务分别进入不同的执行环境, 同步任务进入主线程, 即主执行栈, 异步任务进入任务队列. 主线程内的任务执行完毕至为空时,
回去任务队列读取对应的任务, 推入主线程执行. 上述过程的不断重复就称之为事件循环(Event Loop)

<>宏任务和微任务

在异步任务中并不像同步任务按顺序执行, 而是再细分为宏任务(macro-task)和微任务(micro-task)

每一次Event Loop触发并开始执行异步任务时, 流程如下:

总结就是:

* 执行一个宏任务时, 遇到微任务, 会把微任务加入到微任务的事件队列中
* 当宏任务执行完成后, 再开始依次执行微任务事件队列中的所有微任务
常见的宏任务有:

* setTimeout/setInterval
* script(可以理解为外层的同步代码)
* I/O操作(node.js)
常见的微任务有:

* Promise的方法
* Object.observe(已废弃, Proxy对象替代)
* process.nextTick(node.js)
* MutaionObserver
<>实战

读万卷书, 行万里路, 有没有理解掌握, 实战一下便知
console.log('global') for (var i = 0;i < 3;i ++) { setTimeout(function() {
console.log(i) },i*1000) console.log(i) } new Promise(function (resolve) {
console.log('promise1') resolve() }).then(function () { console.log('then1') })
setTimeout(function () { console.log('timeout2') new Promise(function (resolve)
{ console.log('timeout2_promise') resolve() }).then(function () { console.log(
'timeout2_then') }) }, 0)
分析:

* 从上往下执行, 第一个同步任务, 输出’global’
* 进入循环, 遇到setTimeout, 将其回调函数加入到异步任务队列中

* EventTable: [setTimeout(1s), setTimeout(2s), setTimeout(3s)]
* 执行log函数, 输出i, 注意这里使用var声明的i
* 循环三次, 所以依次输出0, 1, 2
* 执行Promise, 执行log函数, 输出’promise1’
* 将Promise.then加入到异步任务队列中

* EventTable: [ setTimeout(0ms), setTimeout(1000ms), setTimeout(3000ms),
Promise.then ]
* 宏任务队列: []
* 微任务队列: [ Promise.then ]
* 将setTimeout加入到异步任务列中
* EventTable: [ setTimeout1(0ms), setTimeout1(1000ms), setTimeout1(3000ms),
Promise.then, setTimeout2(0ms) ]
* 宏任务队列: []
* 微任务队列: [ Promise.then ]
* 先执行微队列中的任务, 输出’then1’
* EventTable: [setTimeout1(0ms), setTimeout1(1000ms), setTimeout1(3000ms),
setTimeout2(0ms)]
* 宏任务队列: []
* 微任务队列: []
* 微队列清空, 开始宏队列, 执行setTimeout的回调函数, 因为是var声明的遍历, 所以此时的i已经变成3, 输出
setTimeout1(0ms)的3
* EventTable: [ setTimeout1(1000ms), setTimeout1(3000ms), setTimeout2(0ms) ]
* 宏任务队列: []
* 微任务队列: []
* 根据时间顺序, Event Table中下一个执行的是seTimeout2(0ms), 执行log函数, 输出’timeout2’
* 执行Promise的函数体, 输出’timeout2_promise’
* EventTable: [ setTimeout1(1000ms), setTimeout1(3000ms), ]
* 宏任务队列: []
* 微任务队列: [ Promise2.then ]
* 执行Promise.then, 输出’timeout2_then’
* EventTable: [ setTimeout1(1000ms), setTimeout1(3000ms) ]
* 宏任务队列: []
* 微任务队列: []
* 依次执行定时器, 输出3, 3
输出:

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信