事件循环,同步、异步,宏、微任务

现阶段来说,JS 的主要运行环境包含两个:

  1. 浏览器
  2. Node.js

事件循环机制

1、分类分为两种:

  1. 浏览器内部的事件循环机制。
  2. Node.js内部的事件循环机制。

2、什么是事件循环?

  1. JS是单线程,所以就会导致代码的阻塞,为了防止这种情况,我们会把代码分为同步和异步
  2. 同步代码是交给JS引擎执行,异步代码交给宿主环境(浏览器/Node,他们是支持多线程的)
  3. 同步代码放入执行栈中执行,异步代码等待时机成熟送入任务队列排队(自我理解时机成熟是比如定时器时间到了或者点击事件被触发了)
  4. 执行栈同步代码执行完毕之后,会去任务队列看是否有异步任务,有就送到执行队列,这样反复循环查看的过程,我们称为事件循环

3、执行顺序:

●首先执行同步代码,它是在执行栈里面去执行的

●然后是微任务中的异步代码去微任务队列排队,先进先出

●宏任务中的异步代码去宏任务排队,先进先出

●当执行栈里面的代码执行完了之后,就会去看微任务队列,利用事件循环、先进先出将微任务推到执行栈全部执行完之后,再去看宏任务队列,利用事件循环,先进先出将宏任务推到执行栈执行

4、异步任务有哪些

在浏览器端,我们通常可能遇见的异步操作有:

  • 计时器
  • 事件监听
  • 异步请求

到了 Node.js 方面,跟用户有关的鼠标和键盘操作的用户事件监听虽然没了,却多了很多服务端特有的异步任务。

  • 文件读写相关的 I/O 任务
  • 线程相关的 process.nextTick
  • 服务相关的 server.close,socket.on('close', ...)

5、node.js事件循环机制相比于浏览器内部的事件循环机制的区别?

首先,它重新给宏任务分了类。
其次,它添加了任务阶段的概念。

相当于在浏览器里,宏任务们不分组,只要是宏任务,大家都待在一起,执行时按照入队顺序。到了 Node.js 里,不同的宏任务被分了组,只有前一组执行结束,后一组才有执行的机会。

举一个具体的例子吧。

计时器队列内有 3 个待执行回调,系统任务队列内有 5 个待执行回调,I/O 队列内有 2 个,那么等事件循环函数开始执行时,它不会把这些任务混杂在一起,先后去执行,它会先去执行计时器队列内的回调,等计时器队列的三个回调执行结束,它再去执行系统任务回调,之后来到 I/O。

setTimeout(() => {
    console.log('宏任务 timers 阶段:timeout1')
    Promise.resolve().then(function () {
        console.log('微任务:promise1');
    });
}, 0);
setTimeout(() => {
    console.log('宏任务 timers 阶段:timeout2')
    Promise.resolve().then(function () {
        console.log('微任务:promise2');
    });
}, 0);

于是在浏览器,这段代码的输出依次是:

  1. 宏任务 timers 阶段:timeout1
  2. 微任务:promise1
  3. 宏任务 timers 阶段:timeout2
  4. 微任务:promise2

但到了 Node.js 11 之前的环境里,情况变得不太相同,在这里,这段代码的输出内容是:

  1. 宏任务 timers 阶段:timeout1
  2. 宏任务 timers 阶段:timeout2
  3. 微任务:promise1
  4. 微任务:promise2

这是因为,在 Node.js 11 之前的环境里,事件循环会先将一个阶段的所有任务先清空,再去检查微任务队列的内容,在这里,代码的执行次序如下:

  1. 同步代码执行结束后,timers 阶段多出两条计时任务。
  2. 时间到了,两条计时任务的回调函数,先后被添加进 timers 阶段的待执行回调队列中。
  3. 事件循环来到 timers 阶段,发现任务队列不为空,于是,先执行第一条计时任务的回调函数:输出 timeout1,将输出 promise1 添加进微任务队列;再执行第二个计时任务的回调函数:输出 timeout2,将输出 promise2 添加进微任务队列。
  4. timers 阶段的回调队列被清空,往下个阶段进发之前,先去检查微任务队列,发现微任务队列不为空,按照顺序依次执行,promise1promise2 也相继被输出。

什么是同步任务?什么是异步任务?

同步任务是按照代码顺序执行的任务,执行结果会同步返回,而异步任务是不按代码顺序执行的任务,执行结果不会立即返回,而是通过回调函数或者Promise等方式返回。

什么是微任务?什么是宏任务?它们有什么区别?

微任务和宏任务都是异步任务,宏任务是指在主线程之外的任务,比如定时器、事件回调等,而微任务是指在当前任务之后立即执行的任务,比如Promise的then方法和MutationObserver的回调函数等。宏任务和微任务的区别在于宏任务在任务队列中排队,每次只执行一个任务,而微任务在任务队列之后执行,每次执行所有微任务。

  • 宏任务:setInterval、setTimeout、setImmediate、Ajax、DOM事件、异步函数、I/O、UI渲染等。
  • 微任务:process.nextTick、MutationObserver、Promise.then catch finally

简单来说,微任务队列的优先级高于宏任务队列

微任务队列不为空的情况下,JS 引擎优先执行微任务队列的内容,等微任务队列空了,它才会去执行宏任务队列的内容。

参考:JS 事件循环机制 - 简书

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值