JS事件循环机制

一、介绍

JavaScript事件循环机制是JavaScript中处理异步操作的一种机制。它基于事件队列和事件循环的概念,用于管理和执行异步任务。

当JavaScript代码执行时,同步任务会立即执行,而异步任务会被放入事件队列中。事件队列是一个先进先出的数据结构(队列),用于存储待执行的异步任务。

事件循环是一个持续运行的过程,它会不断地从事件队列中取出任务并执行。具体的执行过程如下:

  1. 执行同步任务:JavaScript引擎会按照代码的顺序执行同步任务。
  2. 执行微任务:在同步任务执行完毕后,JavaScript引擎会检查微任务队列。微任务是一类特殊的异步任务,它们的优先级比普通异步任务更高。如果微任务队列不为空,引擎会依次执行微任务,直到微任务队列为空。
  3. 执行宏任务:如果微任务队列为空,引擎会检查宏任务队列。宏任务包括定时器回调、事件回调等。引擎会选择最早进入队列的宏任务执行其回调函数。
  4. 更新渲染:在执行完宏任务后,如果浏览器需要进行页面渲染,会进行页面重绘和重排。
  5. 重复上述步骤:重复执行上述步骤,直到事件队列和微任务队列都为空。

二、同步任务与异步任务

JavaScript是一门单线程语言,但是单线程并不意味着阻塞。实现单线程非阻塞的方式就是事件循环机制。在JavaScript中,所有的事件都可以分为同步任务和异步任务。

  • 同步任务:立即执行的任务。同步任务一般会直接进入到主线程执行。
  • 异步任务:异步执行的任务,比如ajax请求、setTimeout定时器等。

任务进入执行栈,会先判断当前任务是同步任务还是异步任务,如果是同步任务则会进入到主线程,立即执行;异步任务会先放到Event Table,注册回调函数到Event Queue。等待所有的同步任务执行完后,主线程会去Event Queue中读取异步任务到主线程中执行,这个过程的不断重复就是事件循环。
在这里插入图片描述

三、微任务和宏任务

微任务在DOM渲染前触发,宏任务在DOM渲染后触发

**宏任务:**由浏览器规定的

  • setTimeout
  • setInterval
  • Ajax
  • DOM事件

**微任务:**由ES6语法规定的

  • Promise
  • async
  • await

微任务和宏任务的执行机制:
执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中;当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完。
在这里插入图片描述
例题:

 
console.log(1)setTimeout(()=>{
    console.log(2)},0)
new Promise((resolve,reject)=>{
   console.log(3)resolve()
}).then(()=>{
   console.log(4)})
console.log(5)

执行过程为:

(1)①是同步任务,直接打印1,

(2)②为宏任务,

(3)③是同步任务,直接打印3,

(4)④是微任务,放入微任务队列,后面再执行

(5)⑤是同步任务,直接打印5.

(6)本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,④是微任务,执行打印4

(7)一次宏任务执行完,再去执行新的宏任务,即定时器宏任务,打印2

所以最终打印的结果是1–>3–>5–>4–>2

四、async与await

async用于声明异步函数,await用于等待异步任务执行

async函数返回一个promise对象,await命令后面是一个Promise对象,返回该对象的结果。如果不是Promise对象,直接返回对应的值,不管await后面跟着什么,都会阻塞后面的代码!!

await的执行机制:await fn():会立即执行fn(),但是会阻塞fn()后面的代码(加入微任务队列)

例题:

async function async1() {
    console.log('async1 start')await async2()②
    console.log('async1 end')}
async function async2() {
    console.log('async2')}
console.log('script start')setTimeout(function () {
    console.log('settimeout')})
async1()new Promise(function (resolve) {
    console.log('promise1')resolve()
}).then(function () {
    console.log('promise2')})
console.log('script end')

第一轮循环:先执行⑤,打印出:script start,setTimeout为宏任务,放入宏任务队列;执行⑦,进入async1(),先打印:async1 start,遇到await会阻塞后面的语句执行,所以将③放入微任务队列,立即执行②,打印出async2;Promise.then()为微任务,⑨放入微任务队列,Promise立即执行打印:promise1,接着向下执行打印script end

宏任务:setTimeout

微任务:③、⑨

所以最终打印的结果是:script start–>async1 start–>async2–>promise1–>script end–>async1 end–>promise2–>settimeout

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值