前言JS真的很酷(认真脸),有没有想过机器是怎么解析JS代码的?作为一个JS开发者,一般我们不需要直接和编译器打交道,但是如果能够了解其中的基本原理,相信对以后的工作和学习会有一定的帮助!本文介绍的知识主要是基于Node.js和基于Chromium的浏览器使用的V8引擎生成抽象语法树。当HTML解析器遇到脚本标签时,它会加载其中的代码。代码可以从网络请求、缓存或ServiceWorker加载。由于代码是以字节流的形式返回的,所以在下载代码的时候会交给字节流解码器。词法分析生成抽象语法树的第一阶段是tokenize,也称为词法分析字节流decoder会先从代码字节流中创建token(令牌)注:tokens可以理解为语法上不同可能细分的,最小的单个字符或字符串)。例如:0066解码为f,0075解码为u,0063解码为c,0074解码为t,0069解码为i,006f解码为o,006e解码为n后跟一个空格。然后你得到关键字函数!每当创建令牌时,它都会传递给解析器。详见下图:语法分析的第二阶段是解析(parse),也称为句法分析引擎。实际上,使用了两个解析器。一个是预解析器,另一个是解析器。预解析器会先检查源代码是否符合语法规则,不符合则直接抛出错误。这种早期检查机制可以提高解析器的效率。如果没有报错,解析器会根据传入的token创建抽象语法树(AbstractSyntaxTree)并生成执行上下文(以后有机会再讲执行上下文的知识)来生成字节码AST生成后,Down就会交给解释器(interpreter)处理。解释器遍历整个AST并生成字节码。当生成字节码时,AST被移除以节省内存空间。最后我们得到更接近机器码的字节码。这里的字节码是介于AST和机器码之间的代码。它仍然需要通过解释器转换成机器码才能执行。字节码生成后,就可以进入执行阶段了。在执行阶段,引擎会做一些优化操作,一个是即时编译,一个是内联缓存。即时编译虽然字节码很快,但还可以更快!解释器在逐条解释执行字节码时,会分析某段代码是否被执行了多次。这样的代码称为热代码。热点代码和生成的类型反馈(typefeedback)被送到一个叫做优化编译器的东西,它把它转换成计算机可以直接执行的机器码,这样下次执行这段代码时,就不会了需要重新编译,大大提高了代码的执行效率。这种技术也称为即时编译(JIT:JustInTime),上面提到的优化编译器也称为JIT编译器。内联缓存JavaScript是一种动态类型语言,这意味着数据类型可以不断变化。如果JS引擎每次都要检查数据类型,那会很慢。所以引擎使用了一种称为内联缓存的技术。它将代码缓存在内存中,以便将来相同的行为可以直接返回缓存的值。例如,如果您有一个函数被调用100次并且每次都返回相同的值,则引擎将假定它会返回相同的值101次。假设我们有一个求和函数sum,每次取两个数:上面的函数返回3!下次我们调用它时,引擎会假设我们传入了两个Number类型的参数。如果假设正确,则省略动态查询阶段。然后引擎可以直接使用存储在内存中的结果。否则,引擎将恢复解释原始字节码而不是使用优化的机器代码。比如下次我们要调用sum函数,传入一个字符串和一个数字,由于JS是动态类型的,所以不会报错。这意味着数字2将被转换为字符串,最终结果将是“12”。引擎会恢复之前优化过的只接受两个数字的类型反馈,返回字节码运行。全文在此~本文为系列译文:动态图形JavaScript:提升动态图形JavaScript:作用域链(ScopeChain)动态图形JavaScript:事件循环(EventLoop)图形JS:JavaScript引擎【本文】动态GraphicsJS:PrototypalInheritancev8部分内容参考极客时间的一个专栏《浏览器工作原理与实践》:专栏链接:浏览器工作原理与实践想买专栏的可以关注作者的公众号,回复“GeekTime》,返还我的返利~直接注册还可以免费看五讲~参考链接JavaScript可视化:JavaScript引擎
