前序

作为一个有理想有抱负的前端攻城狮,想要走向人生巅峰,我们必须将我们使用的功法练到天人合一的地步。我在们日常工作中,使用最多的语言就是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 文件时,浏览器会先把全局执行上下文中的表达式、和被调用的函数执行完成,接着再执行放入 微任务队列中的函数,最后执行放入宏任务队列的函数。

代码执行步骤详细描述

  1. 执行这一步打印 Global context;
  2. 执行 fn 方法,首先打印 ‘fn start’
  3. 接着把setTiemout 里的匿名函数放入到宏任务队列中,
  4. 接着执行Promise 并把resolve代表的函数放入微任务队列中,最后打印 ‘fn end’
  5. 接着执行全局中的setTimeout 并把里面的匿名函数放入宏任务队列中
  6. 接着执行全局中的 Promise 并把resolve 代表的函数放入微任务队列中
  7. 接着打印 ‘f’,这个时候 call-stack (调用堆栈)中的代码已经执行完毕,就会去执行第一个放入微任务队列中的函数,及在第4步中的放入的微任务,打印 ‘d’,接着执行第二个放入微任务队列中的函数,及在第6步中放入到微任务队列中的函数,打印 ‘h’
  8. 这个时候微任务队列中的任务已经全部执行完成,接着就会执行宏任务队列中的函数,即fn函数里的setTiemout中的匿名函数,打印 'c’,并把 Promise中的的a所代表的的函数放入微任务队列中。这是微任务队列中就有函数了,这是应该去执行微任务队列中的函数,所以这时就会打印 ‘hello world’,
  9. 这时候微任务队列也为空了,就会去执行宏任务队列中的函数,这时候全局的setTiemout的匿名函数就执行了,打印 ‘macro task 2’,并把函数中的 Promise 中的 a 所代表的函数放入微任务队列中,这是微任务队列也就有了可执行函数,所以现在就会执行微任务队列中的函数,打印 'hello girl’

因为讲的非常详细,所以可能显得啰嗦了,希望大家别介意。由于本人水平有限,如有不当之处还望斧正,以免误人子弟。

深入浅出的JS执行机制(图文教程)的更多相关文章

  1. JS学习笔记:(三)JS执行机制

    首先我们先明确一点:JavaScript是一门单线程语言.单线程也就是说同一时间只能执行一个任务,所有的任务都必须排队顺序执行.那么如果一个任务耗时很长,阻塞了其它任务的执行,就会给用户造成不友好的体 ...

  2. 浅谈js执行机制

    关于js执行机制,老早之前就一直想写篇文章做个总结,因为和js执行顺序的面试题碰到的特别多,每次碰到总是会去网上查,没有系统地总结,搞得每次碰到都是似懂非懂的感觉,这篇文章就系统的总结一下js执行机制 ...

  3. 从一道看似简单的面试题重新理解JS执行机制与定时器

     壹 ❀ 引 最近在看前端进阶的系列专栏,碰巧看到了几篇关于JS事件执行机制的面试文章,因为我在之前一篇 JS执行机制详解,定时器时间间隔的真正含义 博文中也有记录JS执行机制,所以正好用于作为测试自 ...

  4. JS执行机制详解,定时器时间间隔的真正含义

     壹 ❀ 引 通过结果倒推过程是我们常用的思考模式,我在上一篇学习promise笔记中,有少量关于promise执行顺序的例子,通过倒推,我成功让自己对于js执行机制的理解一塌糊涂,js事件机制,事件 ...

  5. js执行机制

    js是单线程的,为什么可以执行异步操作呢? 这归结与浏览器(js的宿主环境)通过某种方式使得js具备了异步的属性. 区分进程和线程: 进程:正在运行中的应用程序.每个进程都自己独立的内存空间.例如:打 ...

  6. 浏览器中js执行机制学习笔记

    浏览器中js执行机制学习笔记 RiverSouthMan关注 0.0772019.05.15 20:56:37字数 872阅读 291 同步任务 当一个脚本第一次执行的时候,js引擎会解析这段代码,并 ...

  7. JS 执行机制笔记

        js同步和异步同步 前一个任务结束以后再执行下面一个任务,程序的执行顺序与任务的排列顺序是一致的 同步任务都在主线程上执行,形成一个执行线 异步 前一个任务没结束之前程序还可以执行别的任务 j ...

  8. 摘录和再编:彻底弄懂JS执行机制

    网文: https://juejin.im/post/59e85eebf265da430d571f89 并发模型和事件循环:https://developer.mozilla.org/zh-CN/do ...

  9. JS执行机制--事件循环--笔记

    JS的解析是由浏览器中的JS解析引擎完成的.JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始.但是又存在某些任务比较耗时,如IO读写等, ...

随机推荐

  1. Java中把对象、对象bean、list集合、对象数组、Map和Set以及字符串转换成Json

    对象转换为Json 对象bean转换为Json List集合转换为Json 对象数组转换为Json Map集合转换为Json Set集合转为Json 字符串转换为Json 把Java对常用的一些数据转 ...

  2. hadoop知识点总结(二)hdfs分布式文件系统

    1, hdfs设计:减少硬件错误的危害,流式数据访问,大规模数据集,简单的一致性模型 2,特点: 1)移动计算的代价比移动数据的代价低 在异构的软硬件平台间的可移植性 2)局限性 不适合低延迟性数据访 ...

  3. sqlite安装与封装后编译

    ========================安装sqlite=================官网下载安装包*.tar.gz格式./configure --prefix=/usr/server/s ...

  4. 小白搭建WNMP详细教程---MYSQL安装与设置

    MYSQL的安装请参考WAMP中的mysql的安装教程,两者是一样的. https://www.cnblogs.com/missbye/p/12050312.html

  5. DolphinScheduler1.3.2源码分析(二)搭建源码环境以及启动项目

    前置依赖组件安装 找一台服务器,或者本地的虚拟机,然后在服务器上安装好jdk,zookeeper,mysql. 1.源码调试环境搭建 源码环境搭建可以参考DolphinScheduler官方网站的开发 ...

  6. python里正则表达式基础及注意事项

    感觉正则匹配是一件很酷的事,用得好的话可以极大地提高编程效率.虽然在html中BeautifulSoup更好用一些,但有时候还是需要使用正则匹配.所以就此做一些学习和使用过程中的笔记. python有 ...

  7. 痞子衡嵌入式:恩智浦MCUX SDK在GitHub上线了

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是恩智浦MCUX SDK 在GitHub上线一事. 其实在差不多一个月前(2021年1月6日),恩智浦MCUX SDK就在GitHub悄悄上 ...

  8. Codeforces Round #651 (Div. 2) A. Maximum GCD(数论)

    题目链接:https://codeforces.com/contest/1370/problem/A 题意 有 $n$ 个数大小分别为 $1$ 到 $n$,找出两个数间最大的 $gcd$ . 题解 若 ...

  9. hdu5726 GCD(gcd +二分+rmq)

    Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). ...

  10. FZU - 1901 Period II (kmp)

    传送门:FZU - 1901 题意:给你个字符串,让你求有多少个p可以使S[i]==S[i+P] (0<=i<len-p-1). 题解:这个题是真的坑,一开始怎么都觉得自己不可能错,然后看 ...