IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 学习笔记:JavaScript事件循环 -> 正文阅读

[JavaScript知识库]学习笔记:JavaScript事件循环

为什么要使用事件循环

JavaScript基于单线程执行,所以任务都是一个一个执行的,开始执行任务直到处理完成之前不会被打断,如果某个任务执行的时间很长,会阻塞页面。

那不想出现阻塞页面的情况怎么办呢?使用异步呗,让这个事件先到一边去完成,等完成了再回来汇报结果,这样就不会阻塞页面了。

但是要怎么回来?什么时候回来?这个就需要事件循环来解决。

事件循环基于两个基本原则

  • 一次处理一个任务
  • 一个任务开始后直到运行完成,不会被其他任务中断

事件循环的机制

任务是一个一个执行的,而且一次只能解决一个,这能怎么办?排队呗!开辟一个队列,第一个到的先接待,其他的就在后面等着呗

事件循环通常至少需要两个任务队列

  • 宏任务队列

    例:创建主文档对象、解析HTML、执行主线JavaScript代码、页面加载输入、定时器事件、网络事件等…

  • 微任务队列

    例:promise回调函数、DOM发生变化等…

在这里插入图片描述

上面这个图很重要!记记记!

注意:单次循环迭代中,只处理一个宏任务,其他宏任务等待下次循环迭代,而队列中的所有微任务都会一次性处理完毕,处理微任务时不能产生新的微任务

微任务相比宏任务来说优先级高,且大部分时候耗时都很小,很快就能处理掉,所以宏任务就只能老老实实排队,微任务就像vip客户,只要你来了,不管来了多少,前面的普通客户处理完毕之后,马上就开始接待vip的客户,等接待完了这些vip客户才继续接待普通客户

小细节

  • 宏任务队列和微任务队列的检测都是独立于事件循环的,这就是说将任务添加到这两个队列中的行为是发生在事件循环外的
  • 所有的微任务会在下一次渲染UI之前执行完成,因为他们的目标是在渲染前更新应用程序的状态

用例子看懂事件循环

使用计时器

计时器能延迟一段代码的运行,延长时间至少是指定的时长

方法描述
setTimeout启动一个计时器
clearTimeout关闭一个计时器
setInterval启动一个间隔计时器
clearInterval关闭一个间隔计时器

观察下面的一段代码,模拟一连串事件的执行过程

/* 假设主线程的代码耗时18ms */

setTimeout(() => {
  /* 假设这个部分的代码耗时6ms */
}, 10)
setInterval(() => {
  /* 假设这个部分的代码耗时8ms */
}, 10)

依据以上的情景,得到以下分析步骤

在这里插入图片描述

分析:

  • 代码设置了两个计时器,一个是单次延时的计时器,一个是循环执行的间隔计时器,两个计时器都是延迟10ms执行
  • 主线程执行耗时18ms
  • 单次延时的计时器的回调函数执行需要耗费6ms
  • 间隔延时的计时器的回调函数执行需要耗费8ms

流程:

  1. 0ms开始时,在事件队列中只存在主线程,立即执行

  2. 执行到10ms时,启动了两个计时器,有两项任务加入事件队列(图中红色部分)

  3. 执行到18ms时,主线程执行完毕,此时没有微任务,开始下一轮事件循环,事件队列不为空,继续执行下一项事件

  4. 执行到20ms时,间隔计时器再次启动,但是此时事件队列中已经存在了尚未执行的耗时8ms事件(红色),所以此次事件不会加入到事件队列中

  5. 执行到24ms时,耗时6ms事件(红色)也处理完毕,此时也没有微任务,继续处理事件队列中的下一项事件

  6. 执行到30ms时,间隔计时器再次启动,此时8ms事件(红色)已经被执行,可以加入新的事件(橙色)进入事件队列

  7. 执行到32ms时,8ms事件(红色)处理完毕,没有微任务,继续执行橙色事件

  8. 执行到40ms时,橙色事件处理完毕,没有微任务,正好间隔计时器此时也启动了,绿色事件加入到了事件队列中,事件队列不为空,则继续执行绿色任务

  9. 执行到48ms时,绿色事件处理完毕,没有微任务,事件队列也是空的,则等待事件加入队列,此时空闲

  10. 执行到50ms时,间隔计时器启动,蓝色事件加入队列,队列此时不为空了,直接执行蓝色事件

  11. 接下来就是在9.和10.之间反复循环

值得注意的是,计时器只能控制任务何时被加入事件队列中,而无法控制何时执行

宏任务与微任务交杂(同步与异步)

console.log(1) //主线程,直接执行

setTimeout(() => { //计时器,加入宏任务队列
  console.log(2)
}, 0)

console.log(3) //主线程,直接执行

setTimeout(() => { //计时器,加入宏任务队列
  new Promise(resolve => {
    console.log(4)
    resolve()
  }).then(() => console.log(5)) //promise回调,加入微任务队列
}, 0)

new Promise(resolve => {
  console.log(6) //主线程,直接执行
  resolve()
}).then(() => console.log(7)) //promise回调,加入微任务队列

//输出 1367245

流程:

  1. 主线程是第一个宏任务,直接输出是1、3、6,主线程任务完成,检查微任务队列,有一个输出7的promise回调函数,则输出7,此时微任务队列为空,继续事件循环
  2. 接着执行第二个宏任务,输出2,完成该宏任务,检查微任务队列,没有微任务,继续事件循环
  3. 执行第三个宏任务,是一个立即执行的promise,输出4,回调函数加入微任务队列,该宏任务完成,检查微任务队列,发现有微任务,执行微任务输出5
    件循环
  4. 接着执行第二个宏任务,输出2,完成该宏任务,检查微任务队列,没有微任务,继续事件循环
  5. 执行第三个宏任务,是一个立即执行的promise,输出4,回调函数加入微任务队列,该宏任务完成,检查微任务队列,发现有微任务,执行微任务输出5
  6. 事件循环的宏任务、微任务队列均为空,等待任务加入队列
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 23:00:40  更:2021-07-14 23:01:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/28 12:08:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码