js【深度解析】代码的执行顺序

代码的分类

我们将每一句要执行的 js 代码当做一个任务,则 js 代码可以按照其执行方式的不同,按下图分类

在这里插入图片描述

  • 同步任务:立即执行的代码
  • 异步任务:延迟执行的代码
    • 微任务:被放入微任务队列(micro task queue)中等待执行的代码

      因为Promise、async 、await 都是 ES6 语法定义的

    • 宏任务:被放入 Web APIs 中等待执行的代码

      因为 setTimeout 、setInterval、ajax、Dom事件都是浏览器定义的

不同类型代码执行的顺序和过程

1. 同步任务

  1. 将其放入调用栈(Call Stack)中
  2. 执行该段代码
  3. 将其从调用栈中移除

除 Promise、async 、await、setTimeout 、setIntervall、ajax、Dom事件之外的代码都是可立即执行的同步任务

2. 微任务

  1. 将其放入微任务队列中等待执行

  2. 待所有同步任务执行完毕,开始按微任务队列依次执行微任务

    将第1个进入微任务队列的微任务放入调用栈中,执行微任务内的代码,将其从调用栈中移除,再将第2个进入微任务队列的微任务放入调用栈中,执行,移除…… 以此类推,直到清空微任务队列。

3. DOM 渲染

微任务队列清空后,便暂停 js 代码的执行,开始尝试渲染 DOM, 若没有 DOM操作,则跳过此步。

因 JS 可修改 DOM 结构 , 所以 js 代码的执行和 DOM 渲染必须共用一个线程,这便导致 js 代码的执行和 DOM 渲染无法同时进行。

4. Event Loop 事件轮询

DOM渲染完毕后,便触发Event Loop,开始事件轮询

5. 宏任务

  1. 将其放入 Web APIs 中,并开始计时

  2. 计时结束后,将其放入回调队列(Callback Queue)

  3. 回调队列中的宏任务,依次被事件轮询到

    将第1个进入回调队列的宏任务放入调用栈中,执行宏任务内的代码,将其从调用栈中移除,再将第2个进入回调队列的宏任务放入调用栈中,执行,移除…… 依此类推,直到清空回调队列。

最终 js 代码的执行顺序

因不同类型的代码可能层层嵌套,所以最终 js 代码的执行顺序可能非常复杂,但总的运行方式,如上文所言,根据代码的不同,将其放入不同的队列或栈中,然后依次执行,核心要领在于

  1. 依次执行可执行的同步任务,直到清空调用栈
  2. 依次执行微任务队列中的微任务,直到清空微任务队列
  3. 暂停 js 代码的执行,尝试渲染DOM,若无DOM操作,则直接进入第4步,若有DOM操作,则待DOM渲染完成,进入第4步
  4. 开始事件轮询,依次执行回调队列中的宏任务(事件轮询会一直进行下去,一旦有新的宏任务计时结束进入回调队列,就会被送去调用栈执行)

简单概括如下图所示:

在这里插入图片描述

自测题

console.log(100)// 宏任务
setTimeout(() => {console.log(200)
})// 微任务
Promise.resolve().then(() => {console.log(300)
})console.log(400)

答案 100 400 300 200

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");
}, 0);async1();new Promise(function (resolve) {console.log("promise1");resolve();
}).then(function () {console.log("promise2");
});console.log("script end");

答案

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

解析:详见代码注释

// 定义函数,先跳过
async function async1() {console.log("async1 start"); // 2await async2(); // 先执行 async2() , 进入 async2 函数内// await 后的代码都是微任务,将其放入微任务队列 --- 微任务 1console.log("async1 end"); // 6
}// 定义函数,先跳过
async function async2() {console.log("async2"); // 3
}// 同步任务
console.log("script start"); // 1// 宏任务 1
setTimeout(function () {console.log("setTimeout"); // 8
}, 0);// 同步任务
async1(); // 进入 async1 函数内// 同步任务 -- Promise 函数体内的代码会立刻执行
new Promise(function (resolve) {console.log("promise1"); // 4resolve(); // Promise 状态变为 resolved , 立即触发了 then 函数
}).then(function () {// then 函数是个微任务,将其放入微任务队列 --- 微任务 2console.log("promise2"); // 7
});// 同步任务
console.log("script end"); // 5// 同步任务执行完毕,开始执行微任务
// 依次执行微任务1 和 微任务 2
// 最后执行宏任务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/525795.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字化转型导师坚鹏:金融科技咨询方法论

金融科技咨询方法论 ——方法、做法、演法、心法 课程背景: 数字化转型背景下,很多机构存在以下问题: 不知道先进的金融科技咨询方法论? 不知道如何运作金融科技咨询项目? 不知道如何汇报咨询项目关键成果&…

机器学习第29周周报 Beyond Dropout

文章目录 week29 Beyond Dropout摘要Abstract一、泛化理论二、文献阅读1. 题目2. abstract3. 网络架构3.1 特征图失真3.2 失真优化 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 全连接层实验4.3.2 卷积网络上的实验 4.4 结论 小结参考文献 week29 Beyond Dropout …

练习ROS动作编程

ROS学习记录:动作编程 引言: ​ 通过本实验,我们将联系我们学过的动作编程,客户端发送一个运动目标,模拟小乌龟运动到目标位置的过程,包含服务端和客户端的代码实现,并且带有实时的位置反馈。 希望你在本次学习过后&am…

Java 可变长参数

可变长参数定义 从 Java5 开始,Java 支持定义可变长参数,所谓可变长参数就是允许在调用方法时传入不定长度的参数。可变长参数允许方法接受任意多个相同类型的参数,在方法内部可以将这些参数视为数组来处理。可变长参数通过省略号&#xff0…

vue 自定义组件绑定model+弹出选择支持上下按键选择

参考地址v-modelhttps://v2.cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model 原文代码 Vue.component(base-checkbox, {model: {prop: checked,event: change},props: {checked: Boolean},template: `…

【SQL】550. 游戏玩法分析 IV (关键点:确定连续两次登录)

前述 常见函数用法示例: DATEDIFF(col1, col2) 1DATE_ADD(MIN(col), INTERVAL 1 DAY)ROUND(3.1415926,3) > 四舍五入得到 3.142 题目描述 leetcode原题:550. 游戏玩法分析 IV 思路 确定连续两次登录统计,保留两位小数 写法一 关键…

c语言,大宗撮合交易中心系统核心模块代码

撮合交易系统(Matching System)常用于大宗交易,如股票、期货等市场,它负责根据买卖双方的报价和数量,自动撮合成交。撮合系统的核心模块通常包括订单管理、价格计算和撮合逻辑等部分。 由于撮合系统的实现复杂且依赖于…

分享MDN前端结构化技能、实践指南、学习资源

前言 MDN课程为成为一名成功的前端开发人员提供了一个结构化的基本技能和实践指南,以及推荐的学习资源。 先看下让人不得不服的书《宝宝的网页设计》(套装共3册) 宝宝的HTML、宝宝的CSS、宝宝的JavaScript 全球首套中英文宝宝编程启蒙书&a…

魔众智能AI系统v2.1.0版本支持主流大模型(讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini)

支持主流大模型(讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini) [新功能] 系统全局消息提示 UI 全新优化 [新功能] JS 库增加【ijs】类型字符串,支持默认可执行代码 [新功能] 分类快捷操作工具类 CategoryUtil [新功能…

【Flink】Apache Flink 常见问题定位指南

Apache Flink 常见问题定位指南 1.问题分析概览1.1 如何分析 Flink 问题 2.常见问题处理2.1 作业自动停止2.2 输出量稳定但不及预期2.3 输出量逐步减少或完全无输出2.4 个别数据缺失2.5 作业频繁重启 3.问题追因技巧3.1 常用工具3.1.1 内存3.1.2 CPU3.1.3 磁盘 I/O3.1.4 网络 I…

AI绘画提示词案例(宠物

目录 1. 雪地猫猫:1.1 提示词:1.2 效果: 2. 趴地猫猫:2.1 提示词:2.2 效果: 3. 长城萨摩耶:3.1 提示词:3.2 效果: 4. 沙发猫猫:4.1 提示词:4.2 效…

linux 交叉编译curl(+openssl)

一、交叉编译openssl 参考博客:点击跳转 二、交叉编译curl 1、源码下载 地址:点击跳转 2、配置 CPPFLAGS"-I/home/gui/gui/openssl/build_arm/include" LDFLAGS"-L/home/gui/gui/openssl/build_arm/lib" LIBS"-ldl" \ …