首页IT科技java引擎模板(图文看懂JavaScritpt引擎V8与JS执行过程)

java引擎模板(图文看懂JavaScritpt引擎V8与JS执行过程)

时间2025-06-19 22:56:07分类IT科技浏览4854
导读:本篇文章通过图文为你介绍了V8引擎大概的执行过程,你可以了解到代码是从扫描器Scaner变成tokens,从解析器Parser变成AST,从解释器变成字节码等等。以及JavaScript代码在执行的过程中,它在内存的情况是如何变化的,让你从更加底层的角度去理解你的js代码是如何运行的。了解这些后你就能从更加底层的角度去理解var的...

本篇文章通过图文为你介绍了V8引擎大概的执行过程             ,你可以了解到代码是从扫描器Scaner变成tokens                    ,从解析器Parser变成AST      ,从解释器变成字节码等等             。以及JavaScript代码在执行的过程中             ,它在内存的情况是如何变化的                    ,让你从更加底层的角度去理解你的js代码是如何运行的                    。了解这些后你就能从更加底层的角度去理解var的变量提升      ,闭包的形成等了      。

浏览器原理

浏览器内核与js引擎

浏览器内核又称“排版引擎             ”       ,“渲染引擎                    ”                    ,“浏览器引擎      ”             ,叫法很多       ,简单来说干的活就是将代码(HTML,XML,CSS,图片等)解析排版布局后输出到显示器让你看到             。

JavaScript引擎是一个专门处理JavaScript脚本的虚拟机                    ,一般会附带在网页浏览器之中                    。

主流浏览器内核与js引擎:

浏览器 内核 js引擎 Safari WebKit javaScriptCore Chrome Blink V8 firefox Gecko SpiderMonkey...

浏览器渲染过程概述

输入网址             ,服务器返回html,浏览器内核开始解析html                    ,遇到link 等之类则会暂停                    ,去下载对应的css或者js      。

首先hmtl会被解析为dom树; 然后css会被解析为cssom规则树; 根据dom树和cssom规则树构建渲染树       。 浏览器根据渲染数据进行布局(回流),此阶段浏览器计算各节点在页面中确切位置和大小             ,也称自动重排                    。 布局后进行绘制                    ,将内容显示在屏幕上             。

渲染引擎不会等所有html解析完成后再去      ,构建render tree             ,而是解析完一部分就显示一部分       。以提高用户体验                    。

V8引擎的执行

V8引擎解析过程概述

BLinK内核遇到js代码后                    ,会以流的形式传递给v8      ,然其开始工作:

首先接收到流后       ,会有扫描器Scanner对其进行词法分析将代码转化为tokens; 然后解析器parser将其转换为AST抽象语法树             。 再由解释器ignition(图中闪电部分)生成字节码再进行执行。 Parser再探:

Parser解析的时并不会进行全量解析(全部解析1.耗时间;2.解析后的字节码需放入内存耗内存)                    ,而是有延迟解析的策略             ,也就是一种按需解析给方案       ,( 理解:首先会Perpaser会解析出所需的最少限度的内容                    ,比如内部有未调用的函数             ,则解析出函数声明,当调用时则paser对该函数进行完整的解析 )                    。

Ignition再探:

Ignition关注的是减少 V8 的内存开销                    ,会进行执行前的优化工作                    。它会将AST进行分析将多次调用的函数标记为热点函数 交由TurboFan进行编译生成优化后的机器码(优化                    ,方便快速调用)执行。而单次调用的函数则会被生成字节码再做执行             。所以它也会有编译过程的,所以也有人对JS是否是解释型语言有争议                    。而正如最新的MDN上的文档说的JavaScript是一种具有函数优先的轻量级             ,解释型或即时编译型的编程语言                    ,应该是最准确的吧      。

V8内存模型

V8的内存主要分为堆和栈两部分      ,用以执行代码             ,和JVM有点类似?             。

堆:

这是最大的内存块                    ,也是垃圾回收(GC)发生的地方                    。

栈:

每个V8进程有一个堆内存      。这是存储静态数据的地方      ,包括方法/函数框架             、原始值和指向对象的指针       。

当然这只是简化版       ,实际的情况也会比这复杂得多(如下):

GC垃圾回收

引用计数:对象有引用指向它                    ,引用就+1             ,引用为0就进行回收                    。但其会产生循环引用             。 标记清除:早期V8中堆内存采用的一种清除算法       ,此会有一个根对象                    ,如V8中全局对象       。垃圾回收器会定时从根开始去找引用的对象             ,没有引用的对象就会回收                    。可以很好解决循环引用的问题             。

JavaScript在内存中的执行过程

执行前准备:

-> 首先,js引擎在执行代码之前会在在堆内存中创建一个全局对象GO(Global Object):

该对象在所有作用域可访问 会有 Date,Math,SetTimeOut,SetInterval,String,Array,Number等 内置window属性指向它本身

-> 然后                    ,JavaScript引擎会在内部创建执行上下文栈ECS(Execution Context Stack)                    ,用于执行代码调用。

开始执行:

-> 首先会创建一个全局执行环境GEC(Global Execution Context),它包含:在paser转成AST的过程中             ,将全局定义的变量                    ,函数加入到GO中      ,初始为undefined                    。(变量作用域提升:全局定义的变量             ,函数会先入GO再执行)                    。

并将其入栈到ECS中。然后逐行执行                    ,进行变量赋值      ,函数执行操作             。

-> 在执行到一个函数时会创建函数执行上下文FEC(Fuction Execution Context)       ,并压入执行上下文栈ECS                    ,它包含三部分:

在解析函数成为AST树结构时             ,会创建AO(Activation Object)包含:形参       ,arguments                    ,函数定义(函数代码)             ,函数指向对象,定义边量; 作用域链:VO(在函数中就是AO对象) + 父级作用域 this绑定的值                    。

准备执行【创建GO 创建ECS 解析全局变量                    ,函数(若变量初始为undefined                    ,若函数则创建函数对象进行存储)】-> 执行代码【遇到函数调用 -> 创建其函数的AO对象 -> 创建其函数执行上下文 -> 执行函数内部代码】

注:在最新的ECMA标准中,变量对象VO             ,该为了变量环境VE                    ,其可以不为对象      ,只要其能存储环境记录             ,其包含的内容也有些差异      。

结合代码示例进行分析

案例一 var name = "shinna_mashiro"; foo(666); function foo(num){ console.log(m); var m = 10; var n = 20; function bar(){ console.log(name) } bar() }

这是通过var声明的变量                    ,而通过let      ,const声明的变量ECMA262对它们是这么描述的:The variables(let 或 const)are created when their containing Lexical Environment is instantiate but may not be accessed in any way until the variables LexicalBinding is evaluated. 这些变量会被创建在包含他们的词法环境(VE -> VO)被实例化时       ,但是是不可以访问的                    ,直到词法绑定被执行             。也就是在FEC创建的时候             ,VE被实例化时就会创建它       ,但是不能被访问                    ,所以提升不了                    。(暂时性死区)

案例二闭包 function makeAdder(count){ return function(num){ retrun count + num; } } var add10 = makeAdder(10); console.log(add10(5));

可以看到在代码执行完后             ,闭包结构中,会一直还有引用在GO中                    ,所以此时不会对其内存进行回收      。

部分参考及补充:

1.Visualizing memory management in V8 Engine (JavaScript, NodeJS, Deno, WebAssembly):https://deepu.tech/memory-management-in-v8/

2.全面分析总结JS内存模型:https://segmentfault.com/a/1190000021996331

3.V8引擎详解:https://juejin.cn/post/6844904146798116871

4.JavaScript到底是解释型语言还是编译型语言?:https://segmentfault.com/a/1190000013126460

5.Blazingly fast parsing, part 2: lazy parsing: https://v8.dev/blog/preparser

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vue 遍历数组对象做成树状(vue 遍历数组) 优选企业网站营销推广(如何实现整站优化和有效推广)