js事件循环机制
创始人
2024-06-02 07:41:54
0

一、同步任务与异步任务

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

同步任务:立即执行的任务。同步任务一般会直接进入到主线程执行。

异步任务:异步执行的任务,比如ajax请求、setTimeout定时器等。

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

二、微任务与宏任务

异步任务分为微任务和宏任务:

微任务:一个需要异步执行的函数,执行时机是在主函数结束之后,当前宏任务结束之前。常见的微任务有:Promise.then、MutationObserver、Object.observe(已废弃,被Proxy对象替代)、process.nextTick

宏任务:宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合。常见的宏任务有:script(外层同步代码)、setTimeout/setInterval、UI rendering/UI事件、postMessage、MessageChannel、setImmediate、I/O(Node.js)

微任务和宏任务的执行机制:

执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中;当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完。

例题:

console.log(1)①
setTimeout(()=>{console.log(2)②
},0)
new Promise((resolve,reject)=>{console.log('new Promise')③resolve()
}).then(()=>{console.log('then')④
})
console.log(3)⑤

执行过程为:

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

(2)②为宏任务,

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

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

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

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

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

所以最终打印的结果是1-->new Promise-->3-->then-->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

第一轮宏任务结束,查看微任务队列,执行所有的微任务③⑨,打印promise2,接着下一轮宏任务。

执行setTimeout,打印settimeout。

第二轮宏任务结束,没有要执行的微任务队列,执行③,打印async1 end

最终打印的结果为script start-->async1 start-->async2-->promise1-->script end-->promise2-->settimeout-->async1 end

上一篇:进程相关概念

下一篇:java--Stream流

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...