前端进阶JS运行原理
2023-06-13 09:15:24 时间
JS运行原理
深入了解V8引擎原理
浏览器内核是由两部分组成的,以webkit为例:
- WebCore:负责HTML解析、布局、渲染等等相关的工作;
- JavaScriptCore:解析、执行JavaScript代码;
官方对V8引擎的定义:
- V8是用C ++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等
- 它实现ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+和使用x64,IA-32,ARM或MIPS处理 器的Linux系统上运行。
- V8可以独立运行,也可以嵌入到任何C ++应用程序中。
V8引擎的架构很复杂 ,我们可以先了解它庞大引擎的一些模块
- Parse模块会将JavaScript代码转换成AST(抽象语法树),这是因为解释器并不直接认识JavaScript代码
- 如果函数没有被调用,那么是不会被转换成AST
- Parse的V8官方文档:https://v8.dev/blog/scanner
- Ignition是一个解释器,会将AST转换成ByteCode(字节码)
- 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)
- 如果函数只调用一次,Ignition会解释执行ByteCode
- Ignition的V8官方文档:https://v8.dev/blog/ignition-interpreter
- TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码
- 如果一个函数被多次调用,那么就会被标记为热点函数,它会被TurboFan转换成优化的机器码,提高代码的执行性能
- 机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执 行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码
- TurboFan的V8官方文档:https://v8.dev/blog/turbofan-jit
V8架构解析图 来自官方
解析代码的步骤:
- 获得到代码之后 V8用流输入通过词法分析,分析成token
- 解析/预解析 来生成一个一个执行节点
- 生成 AST 树
- 转成字节码 如果有热点方法就会走turbofan编译器优化成机械码提升性能
全局代码执行过程
js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
- 该对象 所有的作用域(scope)都可以访问
- 里面会包含Date、Array、String、Number、setTimeout、setInterval等等
- 其中还有一个window属性指向自己
js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈,
他执行的式全局代码块,它的作用就是:
- 为了执行代码构建一个 Global Execution Context GEC 全局上下文
- 将这个构建的上下文加入到执行栈中 也就是将 GEC 放入 ECS中
GEC被放入到ECS中里面包含两部分内容:
- 在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值
- 在代码执行中,对变量赋值,或者执行其他的函数;
每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中,当全局代码被执行的时候,VO就是GO对象了
全局上下文三个关键:
- VO(go)
- 作用域链
- This
执行以下代码过程
var message = "Global Message"
function foo() {
var message = "Foo Message"
}
var num1 = 10
var num2 = 20
var res = num1 + num2
console.log(res);
全局代码执行前
执行代码后
函数代码执行过程
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到EC Stack中
- 当进入一个函数执行上下文时,会创建一个AO对象(Activation Object)
- 这个AO对象会使用arguments作为初始化,并且初始值是传入的参数
- 这个AO对象会作为执行上下文的VO来存放变量的初始化
如下函数执行过程
执行前
执行后
https://img-blog.csdnimg.cn/img_convert/994bd5c4b704e04215dea09f2d428a5d.png
流程为:
- 执行前创建FEC 也就是函数执行上下文
- 创建 AO 对象 name为函数名
- 创建作用域链
- 生成函数对象存放代码
- thisbing(暂无)
- 之后从上到下执行代码
- 执行完成后将name 变为 undefined
作用域和作用域链
当进入到一个执行上下文时,执行上下文也会关联一个作用域链(Scope Chain)
- 作用域链是一个对象列表,用于变量标识符的求值
- 当进入一个执行上下文时,这个作用域链被创建,并且根据代码类型,添加一系列的对象
PS : 作用域会提升 在本身vo没有情况下 会去上层寻找,我们先输出后声明会输出undefined, 这里也印证了
作用域提升小练习
var n = 100
function foo(){
n=200
}
foo()
console.log(n)
N =200
顺序内存查找图如下 :
- 全局代码创建函数 找到 n放入到函数vo中 之后调用foo()
- 在函数调用后找到GO中的n复制
- 函数结束,之后输出n
作用域链也是我们JS闭包的一个重点, js中闭包就是通过作用域链的方式来完成变量可以跨作用域访问的,为我们加快提升了开发的效率 也省去很多麻烦
相关文章
- 字符串的方法_js字符串包含另一个字符串
- 18·灵魂前端工程师养成-JS语法入门
- 微前端01 : 乾坤的Js隔离机制(快照沙箱、两种代理沙箱)
- 前端常见算法(js)「建议收藏」
- js-函数的prototype
- 初识js中的闭包_Js闭包中变量理解
- 基于js原生算法+cocos游戏引擎+uni框架Cloud托管网页:开发2048小游戏域名发布版本
- JS设计模式之原型模式
- 如何利用js生成二维码_前端生成二维码
- js前端 md5加密
- js中四舍五入的方法_JS取整
- 前端js手写面试题看这篇就够了
- js浅拷贝和深拷贝的区别_前端面试深拷贝和浅拷贝
- vue.js客服系统实时聊天项目开发(十九)使用正则将消息格式替换为产品卡片信息
- oc 与 js 互相调用
- 【愚公系列】2023年03月 其他-Web前端基础面试题(JS_高级_47道)
- html prism.js 代码前端高亮、代码美化
- 纯前端仿GPT流式打字效果的js库,类似通义千问或者其他AI界面的打字效果
- js中什么是对象,对象的概念是什么详解编程语言
- JS中怎么调用的值详解编程语言
- JS产生四位随机数的方法详解编程语言
- Linux上的JS压缩工具(js压缩工具linux)
- 从前端JS里请求Redis资源,搭建高性能应用(前端js请求redis)
- 淘系前端架构周刊:Next.js 11.1 发布、Vue.js 3.2 发布
- js静态作用域的功能。
- js刷新框架子页面的七种方法代码
- 按钮JS复制文本框和表格的代码
- js获取坐标通过JS得到当前焦点(鼠标)的坐标属性
- php与js的区别是什么
- js获取checkbox值的方法