事件循环-宏任务与微任务

事件循环(eventloop)

同步和异步

JS是单线程的,也就是说, 同一时间只能做一件事,所有任务需要排队,前一个任务结束之后才会执行下一个任务。

作为浏览器脚本语言,JavaScript的主要用途是和用户互动以及操作DOM,这决定了它只能是单线程

但我们知道,有些任务是耗时的,会阻塞代码的执行。
为了解决这个问题,我们引出了同步和异步的概念。
可以把代码分为同步代码(同步任务)和异步代码(异步代码)。

异步代码(耗时)同步代码(立即执行)
先放入宿主环境(浏览器/Node) ,不必原地等待结果。(并不阻塞主线程继续往下执行,异步结果在将来执行)立即放入JS 引擎(JS主线程) 执行,并原地等待结果
setTimeout(一次性定时器)如console.log(1)
setInterval(定时器)
Ajax/Fetch 事件绑定
Promise里的then、catch …

执行过程(执行栈宿主环境任务队列):

  1. 同步代码放入执行栈中,异步代码放在宿主环境,等待时机成熟送入任务队列( 如绑定的事件被触发或定时器时间到了,对应回调函数送到任务队列)
  2. 执行栈中代码执行完毕,会去任务队列看是否有异步任务,有就送到执行栈执行,反复循环查看执行,这个过程是事件循环(eventloop)
    在这里插入图片描述

宏任务与微任务

概述

任务分为同步任务和异步任务,异步任务又可以分为宏任务和微任务。

在ES5之后,JavaScript引入了Promise,意味着不需要浏览器,JavaScript引擎自身也能够发起异步任务了。所以,JS可以执行同步和异步任务。

宏任务宿主(浏览器、Node) 发起
微任务JS 引擎发起

宏任务微任务
script(代码块)Promise的then/catch
事件
网络请求(Ajax/Fetch)
setTimeout() 一次性定时器/setlnterva() 定时器

注意:Promise本身是同步的,只有里面then/catch的回调函数是异步的

到现在我们可以把代码整体分为三类:

宏任务的异步代码(宿主环境)微任务的异步代码(js引擎)同步代码(js 执行栈/回调栈)
script(代码块)Promise.then() / catch()
事件Async/Await
网络请求(Ajax/Fetch)process.nextTick (node)
setTimeout() 一次性定时器/setlnterva() 定时器Object.observe 等等
setlmmediate 定时器Object.observe
I/OMutationObserver
Ul render

宏任务、微任务执行过程及顺序

  1. 首先执行放在执行栈中的同步代码
  2. 微任务里的异步代码放在微任务队列排队,根据先进先出原则依次执行
  3. 宏任务里的异步代码放在宏任务队列排队,根据先进先出原则依次执行

具体描述
执行执行栈中所有同步代码,执行完就去微任务队列里面看有没有微任务在进行排队,如果有的话,就将微任务通过事件循环的方式,根据先进先出原则依次推到执行栈中执行。一个微任务执行完之后再回到微任务队列里看还有没有在排队的,有的话就再推到执行栈中执行。所有微任务执行完毕之后,再去看看宏任务队列,重复像刚才的执行过程(看有没有排队的,有的话就按先进先出通过事件循环推到执行栈中执行),宏任务队列中所有任务执行完毕之后,整个代码就执行完毕了。

pink老师:微任务是由JS引擎发起的,离了我们JS更近,所以说会优先执行

在这里插入图片描述

有时候看到说是宏任务优先:
是因为script本身就是一个大的宏任务,我们所有的代码的操作其实是在一个大的宏任务里面去执行的

忽略script:同步任务 --> 微任务 --> 宏任务

每当主线程执行完一个宏任务后,不会立即执行下一个宏任务,而是接着先检查微任务队列。

如果微任务队列中存在待执行的任务,主线程会立即执行微任务,直到微任务队列为空。

因为微任务通常包含那些需要在当前逻辑上下文结束后、但在渲染或执行新的宏任务之前必须完成的操作。

总结

事件循环(eventloop):

不断地检查调用栈是否为空,并且如果任务队列中有待处理的任务,就将它们推入调用栈(执行栈)执行。

  1. JS是单线程,防止代码阻塞,我们把代码(任务):同步和异步

  2. 同步代码给js引擎执行,异步代码交给宿主环境

  3. 同步代码放入执行栈中,异步代码等待时机成熟送入任务队列排队

  4. 执行栈执行完毕,会去任务队列看是否有异步任务,有就送到执行栈执行,反复循环查看执行,这个过程是事件循环(eventloop)

宏任务与微任务

宏任务:
  • 宏任务被添加到宏任务队列中。
  • 事件循环在每个迭代开始时,会检查调用栈是否为空。
  • 如果调用栈为空,事件循环从宏任务队列中取出一个任务,推入调用栈执行。
  • 浏览器在宏任务执行后会进行渲染更新。
微任务:
  • 微任务被添加到微任务队列中。
  • 事件循环在每个迭代中,一旦调用栈清空,就会立即执行微任务队列中的所有微任务。
  • 微任务的执行顺序是先进先出,它们会在当前宏任务完成后、下一个宏任务开始前清空队列。
  • 微任务的优先级高于宏任务,这意味着在执行下一个宏任务之前,所有的微任务都会被处理完毕。
执行过程及顺序:

在这里插入图片描述

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值