JavaScript 运行机制

文章目录

    • [JavaScript 运行机制](#JavaScript 运行机制)
    • 目标
    • 知识要点
      • 一、进程与线程
        • [1.1 概念](#1.1 概念)
        • [1.2 区别](#1.2 区别)
        • [1.3 多进程与多线程](#1.3 多进程与多线程)
        • [1.4 JS 为什么是单线程](#1.4 JS 为什么是单线程)
        • [1.5 浏览器](#1.5 浏览器)
          • [1.5.1 浏览器包含哪些进程](#1.5.1 浏览器包含哪些进程)
          • [1.5.2 为什么浏览器要多进程](#1.5.2 为什么浏览器要多进程)
          • [1.5.3 渲染进程](#1.5.3 渲染进程)
            • [1.5.3.1 GUI 渲染线程](#1.5.3.1 GUI 渲染线程)
            • [1.5.3.2 JS 引擎线程](#1.5.3.2 JS 引擎线程)
            • [1.5.3.3 事件触发线程](#1.5.3.3 事件触发线程)
            • [1.5.3.4 定时触发器线程](#1.5.3.4 定时触发器线程)
            • [1.5.3.5 异步HTTP请求线程](#1.5.3.5 异步HTTP请求线程)
      • [二、事件循环(Event Loop)基础](#二、事件循环(Event Loop)基础)
      • 三、宏任务与微任务
        • [3.1 宏任务(macrotask)](#3.1 宏任务(macrotask))
        • [3.2 微任务(microtask)](#3.2 微任务(microtask))
      • [四、完整的事件循环(Event Loop)](#四、完整的事件循环(Event Loop))
      • [五、Promise & async/await](#五、Promise & async/await)
        • [5.1 Promise](#5.1 Promise)
        • [5.2 async/await](#5.2 async/await)

JavaScript 运行机制

原文链接:JavaScript运行机制

目标

1.了解进程与线程的基础概念,明确在浏览器中的进程与线程机制;

2.了解浏览器与Node中的事件循环;

知识要点

一、进程与线程

1.1 概念

进程:CPU资源分配的最小单位。------可以独立运行且拥有自己的资源空间的任务程序。(包括运行中的程序和程序中所用到的内存和系统资源)。

eg:每打开一个软件就会产生一个进程,浏览器中每开一个Tab页也会产生一个进程。进程之间相互独立。

线程:CPU调度的最小单位。------建立在进程基础上的一次程序运行单位。一个进程可以有多个线程。一个程序中可以同时运行多个不同的线程来执行不同的任务。

1.2 区别

进程包含了线程,一个进程可以对应多个线程。线程相当于是进程中的不同执行路线。

调度和切换:线程上下文切换比进程上下文切换要快得多。

1.3 多进程与多线程
  • 多进程:允许同一计算机系统中同时运行两个或两个以上的进程。比如在打开网易云听歌的同时还可以打开编辑器敲代码,而这两个进程之间不会相互干扰。
  • 多线程:指一个程序中包含多个执行流来执行不同的任务,而这多个不同的执行流是并行的。
1.4 JS 为什么是单线程

JS主要用途是与用户互动,以及操作DOM。

如果JS是多进程的话,那么它可以同时在某个DOM节点上添加内容,又可以删除这个节点,从而导致浏览器不知该以哪个为准。

1.5 浏览器
1.5.1 浏览器包含哪些进程

浏览器包含以下进程:

  • Browser进程
  • 第三方插件进程
  • GPU进程(Graphics Processing User)
  • 渲染进程
1.5.2 为什么浏览器要多进程

若浏览器是单进程,那么如果某个Tab页崩溃了,则会导致整个浏览器瘫痪,同理,如果插件崩溃了则会影响整个浏览器,这样体验感非常差。

1.5.3 渲染进程

页面渲染,JS的执行,事件的循环,都在渲染进程中执行,所以需要重点了解渲染进程。

渲染进程是多线程的,以下是一些常用较为主要的线程:

1.5.3.1 GUI 渲染线程
  • 负责渲染浏览器界面,解析html,css,构建DOM树和RenderObject树,布局和绘制等

1.解析html代码转化为浏览器认识的节点,生成DOM树,

2.解析CSS,生成CSSOM(CSS规则树)

3.把DOM Tree 和 CSSOM结合,生成Rendering Tree(渲染树)

  • 当修改元素的颜色或背景色时,页面会重绘
  • 当修改元素尺寸时,页面会回流
  • 当页面需要重绘和回流时,执行GUI线程,绘制页面
  • 回流比重绘成本高
  • GUI渲染线程和JS引擎线程是互斥的

1.当JS引擎线程执行时,GUI渲染线程会被挂起

2.GUI渲染线程会被保存在一个队列中等到JS引擎空闲时立即被执行

1.5.3.2 JS 引擎线程
  • JS 引擎线程就是 JS 内核,负责处理 Javascript 脚本程序
  • JS 引擎线程负责解析 JS 脚本,运行代码
  • JS 引擎线程一直等待队列中的任务到来,然后执行
  • JS 引擎线程和 GUI 渲染线程是互斥的,js 引擎线程会阻塞 GUI 渲染线程
1.5.3.3 事件触发线程
  • 事件触发线程管理着一个事件队列,用来控制事件循环
  • 当js执行碰到事件绑定或一些异步操作时,会交由事件触发线程将对应的事件添加到对应的线程中(如定时器事件会添加到定时触发器线程中),等异步事件有了结果,便把结果添加到事件队列中,等待js引擎线程空闲时来处理。
  • 当对应的事件符合触发条件触发时,该线程会将事件添加到事件队列的队尾,等待JS引擎处理
  • 因为JS是单线程,所以待处理队列中的事件都得排队等JS引擎处理
1.5.3.4 定时触发器线程
  • 当JS代码执行中遇到定时任务(如setTimeout、setInterval),会将该定时器任务交由定时触发线程处理,然后等计时完毕,便将事件添加至事件触发线程的事件队列中,等待JS引擎空闲后处理
1.5.3.5 异步HTTP请求线程
  • 当JS代码执行过程中,若遇到http异步请求,则将该异步请求事件交由异步http请求线程,等异步事件响应成功后(即状态码变更),再将事件添加至事件触发线程的事件队列中等待JS引擎空闲后处理

二、事件循环(Event Loop)基础

  • 1.在js代码执行过程中,从上至下逐行解析,遇到同步代码可直接执行,
  • 2.若遇到定时器任务或异步请求,则将事件添加至事件触发器的事件队列末尾(算作下一次事件循环)
  • 3.当同步任务全部执行完毕,则不断问询事件队列中是否有回调事件,
  • 4.若有,则将事件回调放入执行栈中执行,然后再接着回到步骤1

三、宏任务与微任务

3.1 宏任务(macrotask)

我们可以把每次执行栈中执行的代码当作是一个宏任务(包括从事件队列中取出一个事件回调放到执行栈中执行),每一个宏任务都会从头至尾执行,不会执行其他。宏任务中的代码都是同步的。

由于JS引擎线程和GUI渲染线程互斥,所以浏览器为了宏任务和DOM任务有序的进行,会在每一个宏任务执行完毕后,都会在下一个宏任务执行前,GUI渲染线程开始工作,对页面进行渲染。

常见的宏任务有以下几种:

  • 主代码块
  • setInterval
  • setTimeout
  • setImmediate()-Node
  • requestAnimationFrame() -浏览器
3.2 微任务(microtask)

微任务为在当前宏任务执行后立即执行的任务。

当一个宏任务执行完,会在渲染前,将执行期间所产生的所有微任务都执行完:

*任务执行过程:宏任务->微任务->GUI渲染->宏任务->微任务->GUI渲染->xxx*

以下形式的代码为微任务

  • process.nextTick()-Node
  • Promise.then()
  • catch
  • finally
  • Object.observe
  • MutationObserver

四、完整的事件循环(Event Loop)

五、Promise & async/await

5.1 Promise

new Promise(()=>{}).then()中,前面的new Promise(()=>{})是一个构造函数,这是一个同步任务,后面的.then()才是一个异步微任务:

js 复制代码
new Promise((resolve)=> {
    console.log(1);
    resolve();
}).then(()=> {
    console.log(2)
})
cosole.log(3)
// 1 3 2
5.2 async/await

async/await本质上还是基于Promise的一些封装,而Promise是属于微任务的一种

所以在使用await关键字的效果与Promise.then效果类似,await以前的代码,相当于new Promise的同步代码,await以后的代码,相当于Promise.then的异步

js 复制代码
setTimeout(()=> console.log(4))  // 进入下一次事件循环

async function test(){
  console.log(1)
  await Promise.resolve()
  console.log(2)
}
test()

console.log(3)
// 1 3 2 4
相关推荐
宅小海几秒前
scala String
大数据·开发语言·scala
qq_327342733 分钟前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍4 分钟前
Scala的Array数组
开发语言·后端·scala
心仪悦悦7 分钟前
Scala的Array(2)
开发语言·后端·scala
沉默璇年24 分钟前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder30 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_8827275739 分钟前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
baivfhpwxf202340 分钟前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
许嵩6643 分钟前
IC脚本之perl
开发语言·perl
长亭外的少年1 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin