Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀⚙️JavaScript引擎 #91

Open
reng99 opened this issue Mar 31, 2021 · 0 comments
Open

🚀⚙️JavaScript引擎 #91

reng99 opened this issue Mar 31, 2021 · 0 comments
Labels
blog a single blog

Comments

@reng99
Copy link
Owner

reng99 commented Mar 31, 2021

banner.png

本文翻译自🚀⚙️ JavaScript Visualized: the JavaScript Engine

作为JavaScript开发者,我们不需要编译自己编写的代码。那么,JavaScript引擎到底怎么处理这些JS代码,转换成机器能懂的东西呢?🥳

注意:本文主要是基于Node.jsV8引擎和基于Chromium内核的浏览器。

通过script标签,HTML解析器识别到javascript代码。

javascript代码要么来自网络,要么来自缓存,或者安装的service worker

请求的脚本会作为字节流,当在下载字节流时,字节流解码器(Byte Stream Decoder)会将其解码。

fisrt_byte_stream_decoder.gif

字节流解码器将从已经解码的字节流中生成tokens。比如,0066解码为f0075解码为u006e解码为n0063解码为c0074解码为t0069解码为i006f解码为o006e解码为n。这就是你输入的function

然后将这些tokens传送到语法分析器(parser)和预语法分析器(pre-parser)。

👀下面的gif图并没有表现出pre-parser,后面会提及到

second_send_toparser.gif

引擎使用两种语法分析器:pre-parseparse。为了减少网站的加载时间,引擎会避免马上分析没必要的代码。

parser会分析立刻需要用到的代码,而pre-parser处理之后将会用到的代码。比如一个函数只有在用户点击按钮才会触发,那就没必要将那段代码立马进行编译以加载网站。

基于字节流解码器传过来的tokens,语法分析器会创建nodes节点,这些节点形成一个抽象语法树Abstract Syntax Tree (AST)🌳。

third_abstract_syntax_tree.gif

接着,Interpreter(解释器)会遍历AST,然后基于AST包含的信息生成字节码字节码生成之后,AST会被删除,对应的内存空间被清理。最后会处理成机器能识别的内容。

fourth_interpreter.gif

虽然字节码运行很快了,但是它可以更快。当字节码运行,相关信息就会生成,它可以检测某些行为是否经常发生,以及使用的数据类型。可能你重复调用一个函数多次:那是时候需要进行优化了,这样会跑得更快!🏃🏽‍♀️

字节码和生成的类型反馈会一起发送到优化编译器。优化编译器获取字节码和类型反馈,并从中生成高度优化的机器码。🚀

fifth_optimizing_compiler.gif

JavaScript是一门动态类型语言,这意味着数据类型可以不停地更改。如果JavaScript引擎必须每次去检查数据类型对应的值,那将会很慢。

为了减少解析代码的时间,优化机器码只处理引擎在运行字节码时见过的情况。如果我们反复使用一段代码,一遍又一遍地返回相同地数据类型,那么可以简单地重复使用经过优化的机器代码以加快处理速度。然而,因为JavaScript是动态类型的。同一片段的代码有可能突然就返回了不同类型的数据。如果发生这种情况,机器码会被进行非最佳化,引擎会回退到解析生成的字节码。

假设一个特定的函数到目前为止,已经被调用了100次并返回相同的值。那么引擎会认为在第101次,你调用它的时候,它也将返回这个值。

假设我们有下面这个求和函数,到目前为止,我们一直以数字作为参数来调用它:

numeric_sum.png

上图两数和返回的是数值3!那么下一次我们调用它,它还会假设我们是通过两个数字类型的数值来调用它。

如果上面假设是真的,那么无需进行动态查找了,重复使用经过优化的机器码即可。否则,上面假设不成功的话,它将恢复为原始的字节码,而不是优化的机器码。

比如,我们下次调用sum函数,传递的参数其中一个是字符串,而不是数字。因为JavaScript是动态类型的,所以我们这样做没什么问题。

string_sum.png

上图代码中,意味着数字2将会被强制转换成字符串类型,函数返回字符串12。引擎已经回到执行解析字节码并更新类型反馈的阶段了。

后话

@reng99 reng99 added the blog a single blog label Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blog a single blog
Projects
None yet
Development

No branches or pull requests

1 participant