event loop那些事儿

先来段代码

const p = new Promise((resolve, reject) => {
  console.log(1)
})
console.log(2);
setTimeout(function () {
    console.log(3);
}, 1000);
p.then((data) => {
  console.log(4)
})
console.log(5);
复制代码

让我们来看看打印结果的顺序

1
2
5
4
3
复制代码

因为javascript是单线程的,只有一个主线程。主线程会先执行同步代码,异步操作会被放入一个任务队列中。等到同步代码执行完成之后,再执行异步任务。 常见的异步操作有:

  • Ajax
  • DOM的事件操作
  • setTimeout
  • Promise的then方法
  • Node的读取文件

异步任务又分为宏任务微任务。 常见的宏任务有:setTimeoutsetIntervalsetImmediateMessageChannel 常见的微任务有:Promise的then方法process.nextTickMutationObserver

总结javascript执行顺序如下: 1,若是同步任务,则 主线程中执行;如果是异步任务,就放到一个任务队列里 2,开始执行主线程中的同步任务,直到将主线程中的所有任务都走完,此时同步任务清空了 3,回过头看异步队列里如果有异步任务完成了,就生成一个事件并注册回调,放入主线程中 4,再返回第3步,直到异步队列都清空,程序运行结束

这就是所谓的事件环机制,浏览器和node中的事件环机制有所不同。

浏览器中的事件环


在浏览器的执行环境中,总是先执行微任务,再执行宏任务,再来看看第一段代码,为什么Promise的then方法在setTimeout之前执行?其根本原理就是因为Promise的then方法是一个微任务,而setTimeout是一个宏任务。 执行顺序为: 1,先执行微任务,清空微任务队列 2,再执行宏任务,如宏任务中有微任务,则继续执行微任务,直至清空微任务队列 3,循环上述操作,直至所有任务完成

node中的事件环


图中每一个阶段都代表了一个宏任务队列,在Node事件环中,优先执行微任务,微任务的运行时机是在每一个“宏任务队列”清空之后,在进入下一个宏任务队列之间执行。这是和浏览器的最大区别。

与浏览器事件环有所不同的是:浏览器事件环是遇到微任务会清空整个微任务队列。 Node事件环是清空完一个阶段的宏任务队列之后再清空微任务队列。

来看一段代码:

const fs = require('fs');

fs.readFile('./1.txt', (err, data) => {
    setTimeout(() => {
        console.log('timeout');
    });
    setImmediate(() => {
        console.log('immediate');
    });
    Promise.resolve().then(() => {
        console.log('Promise');
    });
});
复制代码

执行结果为:

Promise
immediate
timeout
复制代码

代码并不复杂,首先使用fs模块读取了一个文件,在回调的内部有两个宏任务和一个微任务,微任务总是优于宏任务执行的,因此先输出Promise。 但是之后的区别为什么先输出immdiate?原因就在于fs读取文件的宏任务在上图中的第4个轮询阶段,当第4个阶段清空队列之后,就该进入第5个check阶段,也就是setImmediate这个宏任务所在的阶段,而不会跳回第1个阶段,因此先输出immedate。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值