javaScript 运行时环境

2023-05-16

js的执行阶段

网页的线程

JS引擎线程: 也称为JS内核,负责解析执行Javascript脚本程序的主线程(例如V8引擎)

事件触发线程: 归属于浏览器内核进程,不受JS引擎线程控制。主要用于控制事件(例如鼠标,键盘等事件),当该事件被触发时候,事件触发线程就会把该事件的处理函数推进任务队列,等待JS引擎线程执行

定时器触发线程:主要控制计时器setInterval和延时器setTimeout,用于定时器的计时,计时完毕,满足定时器的触发条件,则将定时器的处理函数推进任务队列中,等待JS引擎线程执行。 注:W3C在HTML标准中规定setTimeout低于4ms的时间间隔算为4ms。

HTTP异步请求线程:通过XMLHttpRequest连接后,通过浏览器新开的一个线程,监控readyState状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进任务队列中,等待JS引擎线程执行。 注:浏览器对通一域名请求的并发连接数是有限制的,Chrome和Firefox限制数为6个,ie8则为10个。

注意:永远只有JS引擎线程在执行JS脚本程序,其他三个线程只负责将满足触发条件的处理函数推进任务队列,等待JS引擎线程执行, 不参与代码解析与执行。

注意:setTimeout和setInterval浏览器给他们开创了一个延迟队列,当事件到了才放入任务队列

宏任务(task)

一个任务就是指计划由标准机制来执行的任何 JavaScript,如程序的初始化、事件触发的回调等。 除了使用事件,你还可以使用 setTimeout() 或者 setInterval() 来添加任务

这里的MDN中的任务我个人认为就是我们所说的宏任务

script (主代码块)、setTimeout 、setInterval 、setImmediate 、I/O 、UI rendering

宏任务(macro-task)可分为同步任务异步任务

  • 同步任务指的是在JS引擎主线程上按顺序执行的任务,只有前一个任务执行完毕后,才能执行后一个任务,形成一个执行栈(函数调用栈)。

  • 异步任务指的是不直接进入JS引擎主线程,而是满足触发条件时,相关的线程(web APIs)将该异步任务推进任务队列(task queue),等待JS引擎主线程上的任务执行完毕,空闲时读取执行的任务,例如异步Ajax,DOM事件,setTimeout等。

理解宏任务中同步任务和异步任务的执行顺序,那么就相当于理解了JS异步执行机制–事件循环(Event Loop)

事件循环(Event Loop)

事件循环可以理解成由三部分组成,分别是:

  • 主线程执行栈 :执行栈

  • 异步任务等待触发 (web Api 就是事件触发线程,定时器触发线程,HTTP异步请求线程)在等待的过程

  • 任务队列:任务队列(task queue)就是以队列的数据结构对事件任务进行管理,特点是先进先出,后进后出。

事件循环

任务队列进入执行栈是一个一个进入的

setTimeout(()=>{
  console.log('timer1')
  Promise.resolve().then(function() {
    console.log('promise1')
  })
}, 0)

setTimeout(()=>{
  console.log('timer2')
  Promise.resolve().then(function() {
    console.log('promise2')
  })
}, 0)

浏览器端运行结果:timer1 => promise1 => timer2 => promise2 

课外知识点:

setTimeout和setInterval的区别:

  • setTimeout并不一定是在到了指定时间的时候就把事件推到任务队列中,只有当在任务队列中的上一个setTimeout事件被主线程执行后或者上一次执行栈中的任务执行完,才会继续再次在到了指定时间的时候把事件推到任务队列,那么setTimeout的事件执行肯定比指定的时间要久,具体相差多少跟代码执行时间有关

    setTimeout(
    () => {
      console.log('1')
      let arr = []
      for(let i = 0; i < 100000000; i++) {
        arr[i] = i
      }
    },
    1000)

    setTimeout(() => {
      console.log('3')
    },1000)

// 输出1 3 是由时间间隔的 因为处理第一个定时器是要时间的

  • setInterval则是每次都精确的隔一段时间就向任务队列推入一个事件,无论上一个setInterval事件是否已经执行,所以有可能存在setInterval的事件任务累积,导致setInterval的代码重复连续执行多次,影响页面性能。

微任务

process.nextTick(Nodejs) 、promise 、Object.observe 、MutationObserver

微任务是在es6和node环境中出现的一个任务类型,如果不考虑es6和node环境的话,我们只需要理解宏任务事件循环的执行过程就已经足够了,但是到了es6和node环境,我们就需要理解微任务的执行顺序了。 微任务(micro-task)的API主要有:Promise, process.nextTick

微任务

微任务通常来说就是需要在当前 task 执行结束后立即执行的任务

例题

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');

解析

  • 代码块通过语法分析和预编译后,进入执行阶段,当JS引擎主线程执行到console.log('script start');,JS引擎主线程认为该任务是同步任务,所以立刻执行输出script start,然后继续向下执行;

  • JS引擎主线程执行到setTimeout(function() { console.log('setTimeout'); }, 0);,JS引擎主线程认为setTimeout是异步任务API,则向浏览器内核进程申请开启定时器线程进行计时和控制该setTimeout任务。由于W3C在HTML标准中规定setTimeout低于4ms的时间间隔算为4ms,那么当计时到4ms时,定时器线程就把该回调处理函数推进任务队列中等待主线程执行,然后JS引擎主线程继续向下执行

  • JS引擎主线程执行到Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); });,JS引擎主线程认为Promise是一个微任务,这把该任务划分为微任务,等待执行

  • JS引擎主线程执行到console.log('script end');,JS引擎主线程认为该任务是同步任务,所以立刻执行输出script end

  • 主线程上的宏任务执行完毕,则开始检测是否存在可执行的微任务,检测到一个Promise微任务,那么立刻执行,输出promise1和promise2

  • 微任务执行完毕,主线程开始读取任务队列中的事件任务setTimeout,推入主线程形成新宏任务,然后在主线程中执行,输出setTimeout

注意

1.明明说宏任务包含了异步任务.也就是异步Ajax,DOM事件,setTimeout等。那为什么上面例子中的setTimeout不是在宏任务中执行的?

原因:宏任务其实就是执行执行栈中的任务,之所以说宏任务会执行(异步Ajax,DOM事件,setTimeout),那是因为在第一次执行script代码块的时候(异步Ajax,DOM事件,setTimeout),通过相关引擎被推入了任务队列中,在第一次宏任务执行完,继续执行微任务后,接着在执行任务队列的时候(异步Ajax,DOM事件,setTimeout)这里就会从任务队列推送到执行栈中去执行了

2.事件循环是一个连续的过程

console.log(1);
console.log(2);

setTimeout(function(){
    console.log(3);
    setTimeout(function(){
        console.log(6);
    })
})
setTimeout(function(){
    console.log(4);
    setTimeout(function(){
        console.log(7);
    })
})
console.log(5)

同样,先执行栈里的同步代码 1 2 5. 再同样,在第一次执行宏任务最外层的settimeout会放在任务队列里,当执行栈里面执行完成以后,任务队列会推送到栈中执行,3 4。 而嵌套的2个settimeout,会在这一次执行执行栈执行的过程中放在一个新的任务队列中,最后去执行 6 7.

文章参考:GitHub - yygmind/blog: 我是木易杨,公众号「高级前端进阶」作者,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!

例子

多微任务情况

<script>
  async function test () {
    console.log(3)
    await new Promise(resolve => resolve())
    console.log(4)
    await  new Promise(resolve => resolve())
    console.log(5)
    await new Promise(resolve => resolve())
    console.log(6)
  }

  new Promise(resolve => resolve()).then(() => {console.log(2)})

  setTimeout(() => {
    console.log('7')
  }, 0)
  console.log(1)
  test()
  // 1 3 2 4 5 6 7
</script>

由于 await 会产生一个promise的一个微任务队列,就相对与在后面加了给then

当移除 async 和 await的时候

  function test() {
    console.log(3)
    new Promise(resolve => resolve())
    console.log(4)
    new Promise(resolve => resolve())
    console.log(5)
    new Promise(resolve => resolve())
    console.log(6)
  }

  new Promise(resolve => resolve()).then(() => { console.log(2) })


  setTimeout(() => {
    console.log('7')
  }, 0)

  console.log(1)
  test()
  // 1 3 4 5 6 2 7

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javaScript 运行时环境 的相关文章

随机推荐

  • ffmpeg修改视频文件的分辨率

    在本文中 xff0c 我们将展示如何调整任何视频文件的大小 这种方法是在Linux系统 xff08 几乎任何发行版 xff09 中调整视频文件大小的最佳方法之一 xff0c 也是Windows和Mac用户的绝佳替代方案 更改视频文件的分辨率
  • SQLServer安装教程(史上最详细版本)

    下载 安装包已上传至百度网盘 xff0c 安装包里已含注册码 xff0c 下载地址 xff08 含注册码 xff09 链接 xff1a https pan baidu com s 147YRI7DdCqTOTKfe9UNtiA 提取码 xf
  • 通过 GetFileVersionInfo 获取EXE 或 DLL的各种资源

    查找网上资源甚多 xff0c 但无一个代码能用 xff0c 甚憾 自已阅读MSDN资料 xff0c 终于写得下面代码 xff0c 经测试通过 xff0c 若有问题请发邮件给我 xff0c 谢谢 xff01 struct LANGANDCOD
  • Tab控件的使用(二)

    tab控件其实只是提供了一组标签按钮 xff0c 其相互切换有响应的消息 xff0c 而且实现了对这些按钮管理的功能 至于通过这些标签按钮来管理我们自己的界面那就要我们通过其提供的各种方法自己实现了 xff0c 这一方面减轻了tab控件自身
  • (转载)MFC -- radio button 的用法

    本文转自http cao416451347ming blog 163 com blog static 1154556162009102795016258 先为对话框加上2个radio button xff0c 分别是Radio1和Radio
  • Linux给普通用户添加sudo权限

    在对 Linux 进行各种操作时 xff0c 为了安全起见 xff0c 一般不使用root用户直接对系统进行操作 原因 在linux中root的权限非常大 xff0c 比如我们常开玩笑的命令 rm rf xff0c 这都是可以直接执行的 而
  • Linux网络编程:socket、客户端服务器端使用socket通信(TCP)

    1 socket概念 socket xff08 套接字 xff09 xff0c 用于网络中不同主机间进程的通信 socket是一个伪文件 xff0c 包含读缓冲区 写缓冲区 socket必须成对出现 socket可以建立主机进程间的通信 x
  • MySQL client does not support authentication protocol requested by server问题解决

    问题描述 xff1a 1251 Client does not support authentication protocol reuqested by server consider upgrading MySQL client 问题分析
  • kubernetes--集群环境搭建

    本文将搭建一套master node node k8s集群环境 xff0c 需要准备三台至少cpu gt 2G mem gt 2G的虚拟机 xff0c 步骤如下 xff1a 1 在所有节点配置hosts并节点间的连接性 分别在三个节点配置h
  • 数据库服务器的安装与配置

    理论基础 数据库服务器是当今应用最为广泛的一种服务器类型 xff0c 许多企业在信息化建设过程中都要购置数据库服务器 数据库服务器主要用于存储 查询 检索企业内部的信息 xff0c 因此需要搭配专用的数据库系统 xff0c 对服务器的兼容性
  • IDEA刷新与清除缓存

    idea清除缓存 刷新项目 idea刷新与清除缓存的正确菜单 Build Project xff1a 更新Project下所有的Module Build Module xff1a 更新指定的Module Rebuild Project xf
  • VNC远程桌面安装配置

    VNC远程桌面安装配置 服务器 xff1a Linux centos 7 0 客户端 xff1a Windows 10 1 服务器安装vnc服务端2 编辑vnc配置文件3 客户端安装4 解决端口访问的问题 1 服务器安装vnc服务端 直接用
  • 第1章 计算机基础知识

    1 1 计算机的基本概念 xff08 1 xff09 计算机的发展 计算机的诞生 1946年第一台电子数字计算机ENIAC由美国宾夕法尼亚大学研制成功 它是一个庞然大物 xff0c 共有18000个电子管 1500个继电器 xff0c 耗电
  • WIN7系统下搭建Docker,部署ODL与mininet

    1 docker 安装 版本 xff1a 18 03 win7系统下和win10系统稍有不同 安装流程 xff1a https www runoob com docker windows docker install html 由于国外源问
  • Debian10中文环境配置

    在安装系统的时候会有一个语言区域选项 xff0c 不管当时选的什么 xff0c 在这里都可以更改 同时解决中文乱码问题 以下操作最好在root用户下进行 xff0c root用户操作起来方便一些 xff0c 不会被权限困扰 换源 最好在做所
  • Redis删除key

    Redis 删除 key 的方式分为两种 xff0c 一种是单独删除指定的 key xff0c 另一种是根据通配符进行批量删除 1 删除指定的 key 1 登录 Redis 客户端 redis cli 注 xff1a 如果提示 Redis
  • Jlink下载stm32cube生成的程序会出现No Cortex-M SW Device Found错误,下载的第一次没事,第二次就会报错

    Jlink下载stm32cube生成的程序会出现No Cortex M SW Device Found错误 xff0c 下载的第一次正常 xff0c 第二次就会报错的问题 作为写stm32的神器stm32cubemx越来越多人开始使用 xf
  • Hadoop 典型Writable类详解

    Hadoop 典型Writable类详解 Hadoop将很多Writable类归入org apache hadoop io包中 xff0c 在这些类中 xff0c 比较重要的有Java基本类 Text Writable集合 ObjectWr
  • 判断js数据类型的方法

    基本类型 String xff0c Number xff0c Boolean xff0c Undefined xff0c Null xff0c Symbol 引用类型 Object 但是有些时候我们需要的是把数组啊 xff0c 函数啊 xf
  • javaScript 运行时环境

    js的执行阶段 网页的线程 JS引擎线程 xff1a 也称为JS内核 xff0c 负责解析执行Javascript脚本程序的主线程 xff08 例如V8引擎 xff09 事件触发线程 xff1a 归属于浏览器内核进程 xff0c 不受JS引