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

0.0772019.05.15 20:56:37字数 872阅读 291

同步任务

当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码全部执行完毕。

 
call stack

这个同步代码的执行过程可以是无限进行下去的,除非发生了栈溢出,即超过了所能使用内存的最大值。

异步任务

js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...如此反复

 
image.png

事件队列

我们先看两个实验

// 实验一
console.log('进入页面') setTimeout(() => {
console.log('setTimeout1')
}, 0)
new Promise((resolve) => {
console.log('promise')
setTimeout(() => {
console.log('setTimeout2')
resolve()
}, 0)
}).then(() => {
console.log('then')
})
console.log('代码执行结束') /* 打印结果
进入页面
promise
代码执行结束
setTimeout1
setTimeout2
then
*/

  

// 实验二
console.log('进入页面') setTimeout(() => {
console.log('setTimeout1')
}, 0)
new Promise((resolve) => {
console.log('promise')
resolve()
}).then(() => {
console.log('then')
})
console.log('代码执行结束') /*打印结果
进入页面
promise
代码执行结束
then
setTimeout1
*/

  

上面的两个demo中,demo2里在Promise里使用了setTimeout包了一层。造成then方法中的回调函数执行顺序稍有不同。一个在setTimeout之后,一个在setTimeou之前。为什么会造成这样的结果?

因为事件分为 macro-taskmicro-task。不同的事件会进入不同的队列。
也就是说事件队列对应的也有两个,macro queue和 micro queue

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

上文中提到当主线程闲置后,会去事件队列中查找执行回调函数,这个是有一个先后策略的,先micro queuemacro queue。而这里的promise中只有在执行了resolve()后才会向micro queue中push在then方法里写的回调函数。这也是上边两个实验中console.log('then')执行顺序不同的原因,下面是详细的执行顺序:

实验1:
// 主线程开始执行同步代码
进入页面
//遇到setTimeout1异步挂起,接着执行同步代码
promise
//遇到setTimeout2异步挂起,接着执行同步代码
代码执行结束
// 同步代码执行完毕,主线程闲置,检查micro queue为空,检查macro queue 有两个回调函数
setTimeout1
setTimeout2
//执行了resolve(),向micro queue中push回调函数
//同步代码执行完毕,主线程闲置检查micro queue,执行里边的回调函数
then

  

实验2:
// 主线程开始执行同步代码
进入页面
//遇到setTimeout1异步挂起,接着执行同步代码
promise
//执行了resolve(),向micro queue中push回调函数
代码执行结束
// 同步代码执行完毕,主线程闲置,检查micro queue发现有回调函数执行
then
// 同步代码执行完毕, 主线程闲置, 检查micro queue为空,检查macro queue发现有回调函数并执行
setTimeout1

  

总结

不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue。

事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

 

浏览器中js执行机制学习笔记的更多相关文章

  1. js执行顺序——学习笔记

    我们知道有个全局的 window对象,js的一切皆window上的属性和方法.window上有个window.document属性,记录了整个html的dom树,document是顶层. body 和 ...

  2. JS 执行机制笔记

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

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

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

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

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

  5. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

  6. Underscore.js 源码学习笔记(上)

    版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}());  这样的东西,我们应该知道这是一个 IIFE(立即执行 ...

  7. JUC.Lock(锁机制)学习笔记[附详细源码解析]

    锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...

  8. js执行机制

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

  9. 纯JS实现KeyboardNav(学习笔记)二

    纯JS实现KeyboardNav(学习笔记)二 这篇博客只是自己的学习笔记,供日后复习所用,没有经过精心排版,也没有按逻辑编写 这篇主要是添加css,优化js编写逻辑和代码排版 GitHub项目源码 ...

随机推荐

  1. npm常用模块之cross-env使用

    更多npm常用模块使用请访问:npm常用模块汇总 cross-env这是一款运行跨平台设置和使用环境变量的脚本. 为什么需要cross-env? NODE_ENV=production像这样设置环境变 ...

  2. 0014 基于DRF框架开发(02 基类视图 GenericAPIView)

    前端于对数据操作的请求基本上就分为四类:增删改查,即增加.删除.修改.查询. 而DRF把前端请求分为两个大类:带ID参数请求和不带ID参数请求. 不带ID参数请求包括:增加.分布多条查询 带ID参数请 ...

  3. PUT方法写shell

    前言: PUT是http的一个请求方法 PUT的前提,是了解HTTP协议.下面给出HTTP - PUT的一个模板: PUT /test.txt HTTP/1.1 Accept: */* Accept- ...

  4. c#在类里不能使用Response解决方法

    response对应的类是HttpResponse,  在System.Web 命名字间里,   如果你在类中要使用   Response 的话,   需要使用System.Web.HttpConte ...

  5. win10下以管理员身份打开hosts文件

    第一步: 第二步: 第三步:先后执行两个命令cmd        notepad hosts 最后一步:在记事本中修改host文件

  6. C#中怎样在ToolStripMenuItem下再添加子级菜单

    场景 在右键菜单ContextMenuStrip下添加子菜单选项可以通过 ContextMenuStrip menuStrip ToolStripMenuItem mnuChartOption = n ...

  7. k8s部署k8s-dashboard(v2.0.0-rc5)

    部署dashboard 版本问题 dashboard版本更新换代很快,而且每个版本对应的k8s版本都有可能不同,所以第一步要确定版本对应关系. 查看页面可以确认版本对应关系 版本对应不上可能出现很多语 ...

  8. windows 环境变量%SystemDrive%和%SystemRoot%、%AppData%、%LocalAppData%、%TEMP% 等简写

    windows 环境变量%SystemDrive% 和%SystemRoot%.%AppData%.%LocalAppData%.%TEMP% 等简写 假设操作系统安装在 C: 盘 %SYSTEMRO ...

  9. selenium统计网页加载时间

    参考网址: https://blog.csdn.net/thlzjfefe/article/details/99712974 https://blog.csdn.net/weixin_43664254 ...

  10. Linux安装Tomcat,解决不能访问Manager App

      在Windows环境中安装Tomcat时,只需要在Tomcat目录下/conf/tomcat-user.xml文件增加用户就可以了.在Linux系统中添加了username还是不能访问. 一.Li ...