前言这个翻译不错,强烈推荐的原因是它以动画的形式生动的描述了JavaScript引擎的基本原理。图片不是我做的,如有侵权,将被删除。做前端这么久,天天和JS打交道,肯定和我一样觉得JavaScript很酷。但是机器怎么才能真正理解你写的代码呢?从以上的思考点出发,这篇文章就是:带你了解JavaScript引擎的基本原理,看看它是如何处理我们人类友好的JS代码,并把它翻译成机器可以理解的东西。作为一名JavaScript开发者,能够清楚地了解它的流程绝对是一件好事。基本概念在这之前,我们要了解一些JS引擎的基本知识。什么是JS引擎,它为我们做了什么?我们都知道,我们写的代码经过处理,交给了CPU,但是它不理解,不能执行。CPU识别自己的指令集,指令集对应汇编代码。这些指令集我们是不可能写出来的,于是出现了:JavaScirpt引擎可以将JS代码编译成不同CPU(Intel、ARM和MIPS等)对应的汇编代码,这样我们就不用去阅读指令了每个CPU设置手册。当然,编译代码并不是它唯一的功能,代码执行、内存分配、垃圾回收机制等都是它的工作。大致了解一下,我们常见的JS引擎有哪些呢?我发现最知名的一定是V8。至于其他的一些,有兴趣的可以去查资料,比如:SpiderMonkey(Mozilla)JavaScriptCore(Apple)Chakra(Microsoft)IOT:duktape和JerryScriptV8的内容太多了,篇幅有限。待会儿我再发一篇文章再说。太有名了,所以本文介绍的知识主要是基于Node.js和基于Chromium的浏览器使用的V8引擎。主流程图中有很多细节,所以主要分析的是主流程,如图:从图中我们可以总结出几点:生成抽象语法树词法分析语法分析生成字节码执行代码Just-in-timecompilationInlinecachegeneration抽象语法树HTML解析器遇到带有源的脚本标签。此源的代码将从网络、缓存或已安装的服务工作者中加载。响应是作为字节流的请求脚本,由字节流解码器处理。字节流解码器解码正在下载的字节流。解码词法分析生成抽象语法树的第一阶段是tokenize,也叫词法分析。字节流解码器首先从代码字节流中创建令牌。注:token可以理解为语法上不能再细分的最小单个字符或字符串)。例如,0066解码为f,0075解码为u,006e解码为n,0063解码为c,0074解码为t,0069解码为i,006f解码为o,006e解码为n,后面跟一个空格。然后你会发现它们的组合就是函数。这是JavaScript中的保留关键字。创建一个令牌并将其发送到解析器。字节流的其余部分也是如此,如下图所示:词法分析语法分析的第二阶段是语法分析,也叫语法分析。该引擎使用两个解析器:预解析器和解析器。为了减少加载网站所需的时间,引擎会尽量避免解析不需要立即使用的代码。预解析器处理稍后可能使用的代码,而解析器处理立即需要的代码!如果某个函数仅在用户单击按钮后调用,则无需立即编译它以加载网站。代码段。如果用户最终单击按钮,则需要该代码,并将其发送到解析器。解析器根据它从字节流解码器接收到的标记创建节点。通过这些节点,它创建了一个抽象语法树或AST,如图:语法分析值得思考的是,AST是什么?(这是什么数据结构?babel也有这些概念吗?)接下来是解释器,它遍历AST,根据AST包含的信息生成字节码。一旦字节码完全生成,AST就会被删除,从而清理内存空间。最后,我们有了机器可以处理的东西。生成字节码我们刚刚提到解释器浏览AST,根据AST中包含的信息生成字节码,那么这个过程是怎样的呢?一般可以这样理解:AST交给解释器(interpreter)处理,遍历整个AST就会生成字节码。当生成字节码时,AST被移除以节省内存空间。最后我们得到更接近机器码的字节码。这里的字节码是介于AST和机器码之间的代码。它仍然需要通过解释器转换成机器码才能执行。我们通过一张图来看一下它的流程:生成字节码代码执行我们有了字节码之后,就可以进入执行阶段了。尽管编译字节码很快,但它可以更快。当此字节码运行时,会生成信息。它可以检测某些行为是否频繁发生,以及正在使用的数据类型。也许您已经多次调用一个函数:是时候对其进行优化以使其运行得更快。字节码与生成的类型反馈一起被发送到优化编译器。优化编译器获取字节码和类型反馈,并从中生成高度优化的机器代码。这种技术也称为即时编译(JIT:JustInTime),上面提到的优化编译器也称为JIT编译器。具体可以参考下图:Just-in-timecompilationandinlinecachingJavaScript是一种动态类型语言,这意味着数据的类型可以不断变化。如果JavaScript引擎每次都必须检查值的数据类型,那将非常慢。如上所述,该引擎具有一种称为内联缓存的技术。具体过程是这样的:为了减少解释代码的时间,优化后的机器码只处理引擎在运行字节码时看到的情况。如果我们一遍又一遍地使用一段代码,一遍又一遍地返回相同的数据类型,优化后的机器代码可以简单地重用以加快速度。但是,由于JavaScript是动态类型的,因此可能会出现同一段代码突然返回不同类型的数据的情况。如果发生这种情况,机器代码将被取消优化,引擎将回退到解释生成的字节码。假设某个函数被调用了100次,并且到目前为止总是返回相同的值。它将假定您第101次调用它时,它也会返回该值。假设我们有以下函数sum,(到目前为止)每次都以一个值作为参数调用它,如图所示:如果是这样,则不需要动态查找,并且可以重用优化的机器代码.否则,如果假设不正确,它将恢复为原始字节码,而不是优化后的机器码。例如,下次我们调用它时,我们传递一个字符串而不是数字。由于JavaScript是动态类型的,我们可以毫无错误地执行此操作!如图:这意味着数字2将被强制转换为字符串,函数将返回字符串“12”。它回退到执行解释的字节码并更新类型反馈。总结不长,但或多或??少对你有帮助,让你了解JS引擎的执行过程。如果想了解更多,请查看原版V8官网的文档:https://v8.dev/docs我是天天,下期见!!!参考链接[1]庆祝V810周年:https://v8.dev/blog/10-years[2]启动Ignition和TurboFan:https://v8.dev/blog/launching-ignition-and-turbofan[3]了解V8的字节码:https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775[4]V8中的推测优化简介:https://benediktmeurer.de/2017/12/13/an-introduction-to-speculative-optimization-in-v8/[5]JavaScript可视化:JavaScript引擎:https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf[6]V8JavaScript引擎:https://nodejs.dev/learn/the-v8-javascript-engine前言这是一篇很好的翻译,强烈推荐的原因是它以动画的形式生动地描述了JavaScript引擎的基本原理。图片不是我做的,如有侵权,将被删除。做前端这么久,天天和JS打交道,肯定和我一样觉得JavaScript很酷。但是机器怎么才能真正理解你写的代码呢?从以上的思考点出发,这篇文章就是:带你了解JavaScript引擎的基本原理,看看它是如何处理我们人类友好的JS代码,并把它翻译成机器可以理解的东西。作为一名JavaScript开发者,能够清楚地了解它的流程绝对是一件好事。基本概念在这之前,我们要了解一些JS引擎的基本知识。什么是JS引擎,它为我们做了什么?我们都知道,我们写的代码经过处理,交给了CPU,但是它不理解,不能执行。CPU识别自己的指令集,指令集对应汇编代码。这些指令集我们是不可能写出来的,于是出现了:JavaScirpt引擎可以将JS代码编译成不同CPU(Intel、ARM和MIPS等)对应的汇编代码,这样我们就不用去阅读指令了每个CPU设置手册。当然,编译代码并不是它唯一的功能,代码执行、内存分配、垃圾回收机制等都是它的工作。大致了解一下,我们常见的JS引擎有哪些呢?我发现最知名的一定是V8。至于其他的,有兴趣的可以去查资料,比如:SpiderMonkey(Mozilla)JavaScriptCore(Apple)Chakra(Microsoft)IOT:Duktape和JerryScriptV8内容太多,篇幅有限。待会儿再发一篇文章再说。太有名了,所以本文介绍的知识主要是基于Node.js和基于Chromium的浏览器使用的V8引擎。主流程图有很多细节,所以主要分析的是主流程,如图:Picture从图中我们可以总结出几点:生成抽象语法树词法分析语法分析生成字节码执行代码Just-in-timecompilationInlinecacheGeneratinganabstractsyntaxtreeHTML解析器遇到带有源代码的脚本标签。此源的代码将从网络、缓存或已安装的服务工作者中加载。响应是作为字节流的请求脚本,由字节流解码器处理。字节流解码器解码正在下载的字节流。图像解码和词法分析生成抽象语法树的第一阶段是标记化,也称为词法分析。字节流解码器首先从代码字节流中创建令牌。注:token可以理解为语法上不能再细分的最小单个字符或字符串)。例如,0066解码为f,0075解码为u,006e解码为n,0063解码为c,0074解码为t,0069解码为i,006f解码为o,006e解码为n,后面跟一个空格。然后你会发现它们的组合就是函数。这是JavaScript中的保留关键字。创建一个令牌并将其发送到解析器。字节流的其余部分也是如此,如下图所示:image词法分析语法分析的第二阶段是解析,也叫语法分析。该引擎使用两个解析器:预解析器和解析器。为了减少加载网站所需的时间,引擎会尽量避免解析不需要立即使用的代码。预解析器处理稍后可能使用的代码,而解析器处理立即需要的代码!如果某个函数仅在用户单击按钮后调用,则无需立即编译它以加载网站。代码段。如果用户最终单击按钮,则需要该代码,并将其发送到解析器。解析器根据它从字节流解码器接收到的标记创建节点。通过这些节点,它创建了一个抽象语法树或AST,如图:ImageSyntaxAnalysis值得思考的是什么是AST?(这是什么数据结构?babel也有这些概念吗?)接下来就是解释器了,解释器遍历AST,根据AST包含的信息生成字节码。一旦字节码完全生成,AST就会被删除,从而清理内存空间。最后,我们有了机器可以处理的东西。生成字节码我们刚刚提到解释器浏览AST,根据AST中包含的信息生成字节码,那么这个过程是怎样的呢?一般可以这样理解:AST交给解释器(interpreter)处理,遍历整个AST就会生成字节码。当生成字节码时,AST被移除以节省内存空间。最后我们得到更接近机器码的字节码。这里的字节码是介于AST和机器码之间的代码。它仍然需要通过解释器转换成机器码才能执行。我们通过一张图来看一下它的流程:图片生成字Sectioncodecodeexecution有了字节码之后,我们就可以进入执行阶段了。尽管编译字节码很快,但它可以更快。当此字节码运行时,会生成信息。它可以检测某些行为是否频繁发生,以及正在使用的数据类型。也许您已经多次调用一个函数:是时候对其进行优化以使其运行得更快。字节码与生成的类型反馈一起被发送到优化编译器。优化编译器获取字节码和类型反馈,并从中生成高度优化的机器代码。这种技术也称为即时编译(JIT:JustInTime),上面提到的优化编译器也称为JIT编译器。具体可以参考下图:图片即时编译内联缓存JavaScript是一种动态类型语言,也就是说数据的类型可以不断变化。如果JavaScript引擎每次都必须检查值的数据类型,那将非常慢。如上所述,该引擎具有一种称为内联缓存的技术。具体过程是这样的:为了减少解释代码的时间,优化后的机器码只处理引擎在运行字节码时看到的情况。如果我们一遍又一遍地使用一段代码,一遍又一遍地返回相同的数据类型,优化后的机器代码可以简单地重用以加快速度。但是,由于JavaScript是动态类型的,因此可能会出现同一段代码突然返回不同类型的数据的情况。如果发生这种情况,机器代码将被取消优化,引擎将回退到解释生成的字节码。假设某个函数被调用了100次,并且到目前为止总是返回相同的值。它将假定您第101次调用它时,它也会返回该值。假设我们有以下函数sum,(到目前为止)每次都以一个值作为参数调用它,如图所示:代码。否则,如果假设不正确,它将恢复为原始字节码,而不是优化后的机器码。例如,下次我们调用它时,我们传递一个字符串而不是数字。由于JavaScript是动态类型的,我们可以毫无错误地执行此操作!如图:image这意味着将数字2强制转换为字符串,函数将返回字符串“12”。它回退到执行解释的字节码并更新类型反馈。总结不长,但或多或??少对你有帮助,让你了解JS引擎的执行过程。如果想了解更多,请查看原版V8官网的文档:https://v8.dev/docs我是天天,下期见!!!参考链接[1]庆祝V810周年:https://v8.dev/blog/10-years[2]启动Ignition和TurboFan:https://v8.dev/blog/launching-ignition-and-turbofan[3]了解V8的字节码:https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775[4]V8中的推测优化简介:https://benediktmeurer.de/2017/12/13/an-introduction-to-speculative-optimization-in-v8/[5]JavaScript可视化:JavaScript引擎:https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf[6]V8JavaScript引擎:https://nodejs.dev/learn/the-v8-javascript-engine
