JS执行机

182 阅读4分钟

JS基础概念

JS概念

JS是一种基于原型的面向对象语言,其不需要编译可以直接使用,由编译器负责解释

JS特点

  • 面向对象:不同于其他基于类的面向对象语言,JS最初并不支持类,JS现有类的概念属于函数的具象,所以JS其实属于基于原型的面向对象语言
  • 脚本语言(动态语言):只在被调用时进行解释或编译,在程序的运行过程中逐行解释执行
  • 解释性语言:不需要编译即可直接使用,由宿主环境解释执行
  • 事件驱动:用户触发事件后产生相应的回调函数从而触发效果
  • 弱类型&松散类型:声明变量时不需要规定其数据类型,不同类型数据在计算过程中会自动进行转换
  • 单线程与异步处理:JS虽是单线程语言,但是其可以通过webApi处理回调函数来实现异步操作
  • 跨平台:JS依赖于JS解析器,其执行与操作环境无关,所以有良好的跨平台性
  • 安全性:JS本身不允许访问用户的硬盘

JS核心

  • ECMAScript:其为JS的标准与拓展
  • DOM(HTML):其本质上是处理HTML的API,可动态的访问HTML的内容与结构
  • BOM(浏览器):描述与与浏览器进行交互的方法与接口,其由多个对象组成,代表浏览器窗口的window对象为BOM的顶层对象,其余对象都是该对象的子对象

JS执行阶段

一. 语法分析

JS引擎拿到JS代码后首先会构建AST语法树并进行语法检测,出现错误则立即抛出

二. 预编译阶段

创建执行上下文

JS的运行环境分为全局环境与函数环境,每进入一个不同的运行环境都会创建一个相应的执行上下文(EC),JS会使用栈的方式对这些上下文进行处理,形成函数调用栈,栈底为全局执行上下文(Global EC)栈顶为当前执行上下文

  1. 创建变量对象(VO)
    • 创建arguments对象,全局环境与箭头函数环境中没有该过程
    • 检查变量声明,变量声明提升
    • 检查函数声明,函数声明提升,若名称相同则进行覆盖 :创建变量对象只发生在预编译阶段,尚未进入执行阶段的变量对象是无法访问的。进入执行阶段后变量对象(VO)会转为活动对象(AO),此时才能进行访问
  2. 建立作用域链
    • 作用域链由当前环境的变量对象(未进入执行阶段前的VO)与上层环境的一系列活动对象(AO)组成,其保证了当前环境对符合访问权限的变量与函数的有序访问
  3. 根据执行环境确定this指向

函数执行上下文大体格式

funEC = {     		 //浏览器中以类数组展示
  //变量对象
  VO:{
    //arguments对象
    //函数
    //变量
  },
  //作用域链
  ScopChain:[],
  //this指向
  This:window
}


三. 执行阶段

解析参与线程

一共有四个线程参与解析,但是只有JS引擎线程在执行JS程序,其余三个协助JS执行

  • JS引擎线程:唯一真正执行JS的线程
  • 事件触发线程:负责当事件触发时将事件回调函数传入任务队列
  • HTTP请求线程:负责处理HTTP请求
  • 定时器触发线程:负责处理定时器并将回调函数传入任务队列

解析过程

JS引擎维护一个主执行栈并重复代码压栈,执行弹出的操作;当遇到异步任务时则触发事件循环机制,当主任务栈与任务队列为空时执行完成

事件循环机制

首先明确JS中的任务分为

  • 同步宏任务:同步代码
  • 异步宏任务:setTimeout、setInterval等
  • 微任务:promise.then、nextTick()等

具体流程为

  1. JS执行时遇到同步宏任务则直接执行,遇到异步宏任务或微任务则交由WebApi进行处理
  2. WebApi在接收到异步宏任务或微任务后会在合适的时间将其回调函数放入到任务队列中
  3. 当JS主执行栈为空时则会取任务队列中的任务进行执行,执行顺序为微任务->宏任务
  4. 如果在执行回调函数时又出现了新的异步任务则会重复上面的过程,形成一个事件循环

image.png