深入浅出的JS执行机制(图文教程)
前序
作为一个有理想有抱负的前端攻城狮,想要走向人生巅峰,我们必须将我们使用的功法练到天人合一的地步。我在们日常工作中,使用最多的语言就是JavaScript了,为了写出完美的、能装逼的代码,我们必须对JavaScript有一个非常透彻的理解,也只有这样我们才能随心所欲的去编写的代码。好了,废话不多说,接下来我们就来一起来了解一下,在JS中代码的执行机制到底是怎样的呢?
执行机制中的关键词
1.call-stack 调用堆栈
调用堆栈简单来说就是当前文件执行上下文中的表达式以及被调用的函数所构成的(未被调用的函数不存在调用堆栈中)
英文好的同学可以去WIKI百科查看详细讲解:
https://www.en.wikipedia.org/wiki/Call_stack#FRAME-POINTER
2.macro-task 宏任务
宏任务是JS中的异步执行任务,在执行call-stack
时,JS 引擎会将所有宏任务放入宏任务队列中;下面是JS
中的宏任务:
- setTimeout
- setInterval
- setImmediate
- requestAnimationFrame
3.micro-task 微任务
微任务也是JS中的异步执行任务,在执行call-stack
时,JS 引擎会将所有微任务放入微任务队列中;下面是JS
中的微任务:
- process.nextTick
- MutationObserver
- Promise.then
- Promise.catch
- Promise.finnaly
下图是JS
的执行机制简图
通过上图,我们对JS的执行机制应该有了粗略的了解,下面我们通过代码的方式来梳理一下,JS的具体执行流程。
// 1.控制台第一步打印下面的console
console.log("Global context");
function fn(){
console.log("fn start");
// 3.当执行这个setTiemout时,这里的函数将被放入
// 到全局的macro-task(宏任务)队列中
setTimeout(function(){
// 当 micro-task (微任务)队列中的函数执行完毕后就会执行第
// 一个被添加到 macro-task 队列中的函数
// 11. 也就是当前的匿名函数
console.log("c");
},0)
// 4.JS执行到这里时会把resolve代表的函数放入到
// micro-task (微任务)队列中
new Promise(function(resolve){
// 当call-stack (调用堆栈)执行完毕后就会执行第一个被添加
// 到micro-task 队列中的函数
// 9. 也就是执行resolve代表的函数
resolve('d');
}).then(function(s){
console.log(s);
})
// 5.接着执行下面这行代码
console.log("fn end");
}
//2.接着执行fn函数
fn();
// 6.接着执行setTimeout函数
// 当执行这个setTiemout时,这里的函数将被放入
// 到macro-task(宏任务)队列中
setTimeout(function(){
// 12.这里是第二个被添加到 macro-task 队列中的
// 的函数,所以当第一个 macro-task 任务执行完后就会执行这个
// 这个函数,到此为止,所有的 call-stack (调用堆栈)、micro-task
// (微任务)队列、 macro-task (宏任务)队列里的函数全部执行完
// 了,整个 JS 文件里的代码也执行完毕
console.log('macro task 2');
},0);
// 7.接着执行Promise函数
// JS执行到这里时会把resolve代表的函数放入到
// micro-task (微任务)队列中
new Promise(function(resolve){
resolve();
}).then(function(){
// 10.这里是第二个被添加到 macro-task 队列中的
// 的函数,所以当第一个 macro-task 任务执行完后就会执行这个
// 这个函数,这个又是最后一个 micro-task 任务,当它也执行完
// 成的时候,JS 就会去执行在 macro-task 任务队列中的函数
console.log('h');
})
// 8.最后执行下面的console
console.log('f');
上面代码的标注顺序就是代码在JS
中的执行顺序,可能有的朋友会觉得有一点抽象;没关系,下面我们通过对边代码和执行队列图来看看上面代码的JS
执行过程
简要概况一下JS
的执行过程
在执行当前的 JS 文件时,浏览器会先把全局执行上下文中的表达式、和被调用的函数执行完成,接着再执行放入 微任务队列中的函数,最后执行放入宏任务队列的函数。
代码执行步骤详细描述
- 执行这一步打印 Global context;
- 执行 fn 方法,首先打印 ‘fn start’
- 接着把setTiemout 里的匿名函数放入到宏任务队列中,
- 接着执行Promise 并把resolve代表的函数放入微任务队列中,最后打印 ‘fn end’
- 接着执行全局中的setTimeout 并把里面的匿名函数放入宏任务队列中
- 接着执行全局中的 Promise 并把resolve 代表的函数放入微任务队列中
- 接着打印 ‘f’,这个时候 call-stack (调用堆栈)中的代码已经执行完毕,就会去执行第一个放入微任务队列中的函数,及在第4步中的放入的微任务,打印 ‘d’,接着执行第二个放入微任务队列中的函数,及在第6步中放入到微任务队列中的函数,打印 ‘h’
- 这个时候微任务队列中的任务已经全部执行完成,接着就会执行宏任务队列中的函数,即fn函数里的setTiemout中的匿名函数,打印 'c’,并把 Promise中的的a所代表的的函数放入微任务队列中。这是微任务队列中就有函数了,这是应该去执行微任务队列中的函数,所以这时就会打印 ‘hello world’,
- 这时候微任务队列也为空了,就会去执行宏任务队列中的函数,这时候全局的setTiemout的匿名函数就执行了,打印 ‘macro task 2’,并把函数中的 Promise 中的 a 所代表的函数放入微任务队列中,这是微任务队列也就有了可执行函数,所以现在就会执行微任务队列中的函数,打印 'hello girl’
因为讲的非常详细,所以可能显得啰嗦了,希望大家别介意。由于本人水平有限,如有不当之处还望斧正,以免误人子弟。
深入浅出的JS执行机制(图文教程)的更多相关文章
- JS学习笔记:(三)JS执行机制
首先我们先明确一点:JavaScript是一门单线程语言.单线程也就是说同一时间只能执行一个任务,所有的任务都必须排队顺序执行.那么如果一个任务耗时很长,阻塞了其它任务的执行,就会给用户造成不友好的体 ...
- 浅谈js执行机制
关于js执行机制,老早之前就一直想写篇文章做个总结,因为和js执行顺序的面试题碰到的特别多,每次碰到总是会去网上查,没有系统地总结,搞得每次碰到都是似懂非懂的感觉,这篇文章就系统的总结一下js执行机制 ...
- 从一道看似简单的面试题重新理解JS执行机制与定时器
壹 ❀ 引 最近在看前端进阶的系列专栏,碰巧看到了几篇关于JS事件执行机制的面试文章,因为我在之前一篇 JS执行机制详解,定时器时间间隔的真正含义 博文中也有记录JS执行机制,所以正好用于作为测试自 ...
- JS执行机制详解,定时器时间间隔的真正含义
壹 ❀ 引 通过结果倒推过程是我们常用的思考模式,我在上一篇学习promise笔记中,有少量关于promise执行顺序的例子,通过倒推,我成功让自己对于js执行机制的理解一塌糊涂,js事件机制,事件 ...
- js执行机制
js是单线程的,为什么可以执行异步操作呢? 这归结与浏览器(js的宿主环境)通过某种方式使得js具备了异步的属性. 区分进程和线程: 进程:正在运行中的应用程序.每个进程都自己独立的内存空间.例如:打 ...
- 浏览器中js执行机制学习笔记
浏览器中js执行机制学习笔记 RiverSouthMan关注 0.0772019.05.15 20:56:37字数 872阅读 291 同步任务 当一个脚本第一次执行的时候,js引擎会解析这段代码,并 ...
- JS 执行机制笔记
js同步和异步同步 前一个任务结束以后再执行下面一个任务,程序的执行顺序与任务的排列顺序是一致的 同步任务都在主线程上执行,形成一个执行线 异步 前一个任务没结束之前程序还可以执行别的任务 j ...
- 摘录和再编:彻底弄懂JS执行机制
网文: https://juejin.im/post/59e85eebf265da430d571f89 并发模型和事件循环:https://developer.mozilla.org/zh-CN/do ...
- JS执行机制--事件循环--笔记
JS的解析是由浏览器中的JS解析引擎完成的.JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始.但是又存在某些任务比较耗时,如IO读写等, ...
随机推荐
- python3中zip对象的使用
zip(*iterables) zip可以将多个可迭代对象组合成一个迭代器对象,通过迭代取值,可以得到n个长度为m的元组.其中n为长度最短可迭代对象的元素个数,m为可迭代对象的个数.并且每个元组的第i ...
- Geospark-属性字段处理
Geospark将从shapefile.csv等格式文件以及DataFrame中的读取的字段保存到了Geometry的userData字段中,可以通过调用.getUserData()方法获取,他会返回 ...
- Django(视图)
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何 ...
- 7. Linux命令行的通配符、转义字符
1.命令行的通配符 举例:1)列出所有在/dev 目录中以sda 开头的文件 [root@Centos test]# ll /dev/sda* brw-rw----. 1 root disk 8, 0 ...
- jvm系列四类加载与字节码技术
四.类加载与字节码技术 1.类文件结构 首先获得.class字节码文件 方法: 在文本文档里写入java代码(文件名与类名一致),将文件类型改为.java java终端中,执行javac X:...\ ...
- Python 字符串指定位置替换字符
指定位置替换字符 def replace_char(old_string, char, index): ''' 字符串按索引位置替换字符 ''' old_string = str(old_string ...
- three.js cannon.js物理引擎制作一个保龄球游戏
关于cannon.js我们已经学习了一些知识,今天郭先生就使用已学的cannon.js物理引擎的知识配合three基础知识来做一个保龄球小游戏,效果如下图,在线案例请点击博客原文. 我们需要掌握的技能 ...
- Python初学者随笔(一)_ 用Python写的第一个游戏“猜数字”
如标题所写,这篇随笔主要记录下学习Python过程中用Python写的第一个游戏--"猜数字"_跟着"小甲鱼"学Python,链接: https://b23.t ...
- P3195 [HNOI2008] 玩具装箱(斜率优化DP)
题目链接 设\(d[i]\)为将前 \(i\) 个玩具装入箱中所需得最小费用 容易得到动态转移方程: \[d[i] = min(d[j] + (s[i]-s[j]+i-j-1-L)^2), (j< ...
- Codeforces Round #515 (Div. 3) C. Books Queries (模拟)
题意:有一个一维的书架,\(L\)表示在最左端放一本书,\(R\)表示在最右端放一本书,\(?\)表示从左数或从右数,最少数多少次才能得到要找的书. 题解:我们开一个稍微大一点的数组,从它的中间开始模 ...