精华内容
下载资源
问答
  • Go的V8 JavaScript引擎绑定。 特征 线程安全 彻底仔细的测试 布尔值,数字,字符串,对象,数组,正则表达式,函数 编译并运行JavaScript 保存并加载预编译的脚本数据 使用全局对象模板创建JavaScript上下文 在Go...
  • mJS:受限制JavaScript引擎 概述 mJS专为资源有限的微控制器而设计。 主要设计目标是:占地面积小和简单的C / C ++互操作性。 mJS实现了ES6(JavaScript版本6)的严格子集: 任何有效的mJS代码都是有效的ES6代码。 ...
  • V8Js是Google V8 Javascript引擎PHP扩展。 该扩展允许您从PHP的安全沙箱中执行Javascript代码。 可以使用时间限制和/或内存限制来限制执行的代码。 这提供了自信地执行不受信任的代码的可能性。 最低要求 V8 ...
  • 在android上编译v8
  • JavaScript引擎

    千次阅读 2018-06-13 14:02:21
    什么是JavaScript引擎JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中。 什么是虚拟机呢? 虚拟机(英语:virtual machine),在计算机科学中的体系结构里,是指一种...

    什么是JavaScript引擎?

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



    什么是虚拟机呢?

    虚拟机(英语:virtual machine),在计算机科学中的体系结构里,是指一种特殊的软件,可以在计算机平台和终端用户之间创建一种环境,而终端用户则是基于这个软件所创建的环境来操作软件。

    根据虚拟机的运用和直接机器的相关性分为两类:

    • 系统虚拟机,提供一个可以运行完整操作系统的完整系统平台。
    • 程序虚拟机,运行单个计算机程序设计,这意谓它支持单个进程。

    JavaScript引擎就是一种程序虚拟机。

    正在开发的JavaScript引擎有哪些?

    1. V8,用C++编写,开放源代码,由Google丹麦开发,是Google Chrome的一部分,也用于Node.js
    2. JavaScriptCore,开放源代码,用于webkit型浏览器,如Safari ,2008年实现了编译器和字节码解释器,升级为了SquirrelFish。苹果内部代号为“Nitro”的JavaScript引擎也是基于JavaScriptCore引擎的。
    3. Rhino,由Mozilla基金会管理,开放源代码,完全以Java编写,用于HTMLUnit
    4. SpiderMonkey,第一款JavaScript引擎,早期用于Netscape Navigator,现时用于Mozilla Firefox
    5. Chakra (JScript引擎),用于Internet Explorer[11]
    6. Chakra (JavaScript引擎),用于Microsoft Edge
    7. KJS,KDE的ECMAScript/JavaScript引擎,最初由哈里·波顿开发,用于KDE项目的Konqueror网页浏览器中。


    它的作用?

    基本工作是把开发人员写的 JavaScript 代码转换成高效、优化的代码,这样就可以通过浏览器进行解释甚至嵌入到应用中。

    更准确地讲,每个 JavaScript 引擎都实现了一个版本的 ECMAScript,JavaScript 是它的一个分支。随着 ECMAScript 的不断发展,JavaScript 引擎也不断改进。之所以有这么多不同的引擎,是因为它们每个都被设计运行在不同的 web 浏览器、headless 浏览器、或者像 Node.js 那样的运行时环境中。

    对于静态语言来说(Java、C++、C),处理上述事情的是编译器。对应的,JavaScript这种动态语言叫做解释器。
    不同:

    • 编译器:将源代码编译为另外一种代码(比如机器码,或者字节码)
    • 解释器:直接解析并将代码运行结果输出。 比方说,firebug的console就是一个JavaScript的解释器。
      但是很难界定JavaScript引擎是编译器还是解释器。因为像V8引擎,为了提高JS的运行性能,在运行之前会将js编译为本地的机器码,然后再去执行机器码。

    它的组成?

    • 编译器。主要工作是将源代码编译成抽象语法树,然后在某些引擎中还包含将抽象语法树转换成字节码。

    • 解释器。在某些引擎中,解释器主要是接受字节码,解释执行这个字节码,然后也依赖来及回收机制等。

    • JIT工具。一个能够JIT的工具,将字节码或者抽象语法树转换成本地代码,当然它也需要依赖牢记
    • 垃圾回收器和分析工具(profiler)。它们负责垃圾回收和收集引擎中的信息,帮助改善引擎的性能和功效。


    它是如何工作的?

    吸引我们注意的两个主要的引擎JavaScriptCore 和 Google 的 V8 引擎都利用了 NativeScript ,它这两个引擎使用不同的方式处理代码。

    JavaScriptCore:
    源代码=》抽象语法树=》字节码
    1. 词法分析,将源代码分解成一系列具有明确含义的符号或字符串(分词)
    2. 用词法分析器分析这些符号,将其构建成抽象语法树
    3. 解析器生成字节码(编译器可以理解)
    4. 4个JIT(Just-In-Time)进程参与进来,分析和执行解析器所生成的字节码。

    V8:目的提高性能。
    源代码=》抽象语法树=》本地码
    这里写图片描述
    V8引擎并不将抽象语法树转变成字节码或者其它中间表示,没有像Java一样的虚拟机或者字节码解释器。
    这样做的原因?
    主要是为了减少这抽象语法树到字节码的转换时间,这一切都在网页加载时候完成,虽然可以提高优化的可能,但是这些分析可能带来巨大的时间浪费。

    JavaScript引擎与ECMAScript的关系?

    JavaScript引擎就是根据ECMAScript定义的规则解析我们的js代码。
    首先,我们应该知道JavaScript引擎也是程序,我们写的js代码也是程序。如何让程序读懂程序呢?就需要定义规则。ECMAScript就是定义了这一套规则,ECMAScript 262这份文档就定义了JavaScript这门语言的标准,JavaScript就是对ECMAScript的一种实现。


    JavaScript引擎与浏览器的关系?

    JavaScript引擎是浏览器的组成部分之一,不同的浏览器采用了不同的JavaScript引擎。
    对于网页的工作来说,需要两个引擎。渲染引擎JavaScript引擎。它们是两个独立的模块,负责不同的事情。渲染引擎负责网页的渲染;JavaScript引擎负责JavaScript代码执行。

    这里写图片描述
    如上,JavaScript引擎提供调用接口被渲染引擎使用,渲染引擎使用的JavaScript引擎来处理js代码并获得结果。此外,JavaScript引擎需要渲染引擎提供桥接的接口以便能够访问渲染引擎构建的DOM树,操作DOM。(通过复杂且低效的桥接接口访问DOM,对性能来说是一个很大的损失)。

    参考:
    JavaScript运行原理解析
    一篇给小白看的 JavaScript 引擎指南
    为什么JavaScript在现在引擎(V8,JavaScript引擎)能够表现出卓越性
    什么是JavaScript引擎?

    展开全文
  • javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境栈、全局对象、执行环境、变量对象、活动对象、作用域和作用域链等,这些概念正是...
  • 深入JavaScriptJS引擎如何执行JS代码

    千次阅读 多人点赞 2021-04-20 12:09:34
    js引擎在执行js代码时,也会从上到下进行 词法分析、语法分析、语义分析 等处理,并在代码解析完成后生成AST(抽象语法树),最终根据AST生成CPU可以执行的机器码并执行。 除此之外,JS引擎在执行代码时还会进行其它...

    我们大概经常能听到“执行环境”、“作用域”、“原型(链)”、“执行上下文”等内容,它们都在描述什么?

    JS代码的运行

    我们知道了js是弱类型语言,在运行时才确定变量类型。js引擎在执行js代码时,也会从上到下进行 词法分析语法分析语义分析 等处理,并在代码解析完成后生成AST(抽象语法树),最终根据AST生成CPU可以执行的机器码并执行。

    除此之外,JS引擎在执行代码时还会进行其它处理,如 V8 中还有两个阶段:

    • 编译阶段:该阶段会进行执行上下文的创建,包括创建变量对象(VO)(此时会被初始化为undefined)、建立作用域链、确定 this 指向等。每进入一个不同的运行环境。V8 都会创建一个新的执行上下文。
    • 执行阶段:将编译阶段中创建的执行上下文压入调用栈,并成为正在运行的执行上下文。代码执行结束后,将其弹出调用栈。(这里有一个VO - AO的过程:JavaScript对变量赋值时变量被用到,此时变量对象会转为活动对象,转换后的活动对象才可被访问)

    这就引出了两个概念:“执行上下文” 和 “作用域链”。


    JavaScript执行上下文

    由上面我们可以知道:当js代码执行一段可执行代码时,会创建对应的执行上下文。
    首先,js中可执行代码对应着有一个概念:“执行环境” —— 全局环境、函数环境 和 eval
    其次,对于每个执行上下文,都有三个重要属性:

    • 变量对象(即“VO”)
    • 作用域链
    • this

    我们来看两段代码:

    var scope="global scope";
    function checkscope(){
    	var scope="local scope";
    	function f(){
    		return scope;
    	}
    	return f();
    }
    checkscope();
    
    var scope="global scope";
    function checkscope(){
    	var scope="local scope";
    	function f(){
    		return scope;
    	}
    	return f;
    }
    checkscope()();
    

    它们会打印什么?
    scope

    为什么?答案是它们的执行上下文栈不一样!

    什么是“执行上下文栈”?
    当执行一个可执行代码时,就会提前做准备工作,这里的“准备工作”,专业的说法就是“执行上下文”。但随着可执行代码如函数的增多,如何管理那么多的执行上下文呢?所以JS引擎创建了执行上下文栈的概念。
    我们完全可以用数组去模拟其行为(栈底永远有一个全局执行上下文globalContext)

    我们定义一个EStack,首先

    EStack=[globalContext];
    

    然后来模拟第一段代码:

    EStack.push(<checkscope> functionContext);
    EStack.push(<f> functionContext);
    EStack.pop();
    EStack.pop();
    

    而第二段代码是这样的:

    EStack.push(<checkscope> functionContext);
    EStack.pop();
    EStack.push(<f> functionContext);
    EStack.pop();
    

    究其原因,你可能需要先研究一下“闭包”的概念了!

    这里顺便说下“在前端模块化”中怎么实现“长时间保存数据”?
    缓存?不。闭包!


    JavaScript作用域和作用域链

    首先,作用域是指程序中定义变量的区域。作用域规定了如何查找变量,也就是确定了当前执行代码对变量的访问权限。
    作用域有两种:静态作用域动态作用域
    JS采用的静态作用域,也叫“词法作用域”。函数的作用域在函数定义的时候就确定了。

    由上,词法作用域中的变量,在编译过程中会产生一个确定的作用范围。这个作用范围即“当前的执行上下文”。在ES5后我们用“词法环境”替代作用域来描述该执行上下文。词法环境由两个成员组成:

    • 自身词法环境记录:用于记录自身词法环境中的变量对象
    • 外部词法环境引用:用于记录外层词法环境中存在的引用

    我们依然来看一个例子:

    var value=1;
    function foo(){
    	console.log(value);
    }
    function bar(){
    	var value=2;
    	foo();
    }
    bar();
    

    回看上面的定义,该打印什么?

    value

    让我们分析下执行过程:
    执行foo()函数,先从foo函数内部查找是否有局部变量value。如果没有,就根据定义时的位置,查找上面一层的代码,也就是value=1.所以结果会打印1。

    这里面当然不是如此简单能概括的,你可以从执行上下文的角度分析一下。

    建立作用域链

    上面我们说了词法环境(作用域)的两个组成。再结合执行上下文,我们不难发现:通过外部词法环境的引用,作用域可以顺着栈层层拓展,建立起从当前环境向外延伸的一条链式结构。

    再来看一个例子:

    function foo(){
    	console.dir(bar);
    	var a=1;
    	function bar(){
    		a=2;
    	}
    }
    console.dir(foo);
    foo();
    

    由静态作用域,全局函数foo创建了一个自身对象的 [[scope]] 属性

    foo[[scope]]=[globalContext];
    

    而当我们执行foo()时,也会先后进入foo函数的定义期和执行期。在foo函数的定义期时,函数bar的 [[scope]] 将会包含全局内置scope和foo的内置scope

    bar[[scope]]=[fooContext,globalContext];
    

    这证明了这一点:“JS会通过外部词法环境引用来创建变量对象的一个作用域链,从而保证对执行环境有权访问的变量和函数的有序访问。”

    让我们再回头看看执行上下文中的那道题,在前面我们说了它们有什么不同,这里说下为什么它们相同地打印了“local scope”:还是那句话“JS采用的是词法作用域,函数的作用域取决于函数创建的位置” —— JS函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量scope一定是指局部变量,不管何时何地执行 f() ,这种绑定在执行 f() 时依然有效。

    基于作用域链的变量查询

    当某个变量无法在自身词法环境记录中找到时,可以根据外部词法环境引用向外层进行寻找,直到最外层的词法环境中外部词法环境引用为null
    与此相似的是“对象中基于原型链的查找”:

    • 原型:每一个JS对象(null 除外)在创建时就会与另一个对象关联,这个对象就是我们说的原型。每一个对象都会从原型中“继承”属性。
    • 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还找不到,就去找原型的原型,一直到最顶层(__proto__为null)为止

    它们的区别也显而易见:原型链是通过 prototype 属性建立对象继承的链接;而作用域链是指内部函数能访问到外部函数的闭包。不管直接还是间接,所有函数的作用域链最终都链接到全局上下文。

    展开全文
  • JS 引擎初探

    千次阅读 2019-03-28 20:49:52
    JavaScript语言 JavaScript 本质上是一种解释性语言(目前其实是不太准确的)。函数是一等公民。JavaScript的另一个特点(也算是一个缺点)是动态类型,在编译的时候不能够确定每个变量类型,只有根据运行时的环境去...

    概述


    JavaScript语言

    JavaScript 本质上是一种解释性语言(目前其实是不太准确的)。函数是一等公民。JavaScript的另一个特点(也算是一个缺点)是动态类型,在编译的时候不能够确定每个变量类型,只有根据运行时的环境去判断其具体的类型,这就导致了性能问题。
    下面通过一个例子来解释动态类型所带来的性能损失:

    // javascript
    function add(a, b) {
    	return a.x * b.y + b.x * b.y;
    }
    // C++
    int add(Class1 a, Class1 b) {
    	return a.x * b.y + b.x * b.y;
    }
    class Class1 {
    	int x;
    	int y;
    }
    

    当运行C++的代码的时候,根据 Class1 的定义,我们可以知道对象a,b的属性(x, y)的类型,只要平台确定,那确定的类型就会有确定的长度。这样在生成可执行代码的时候就可以直接根据内存地址和相应的偏移量来获得相应的值。所以字符“x”和“y”在执行的时候根本不需要,也就不需要额外的查找地址的工作。

    再看JavaScript的执行,传统的JavaScript解释器一切都是解释执行的,所以效率不会高,即使现在更为高效的JIT(just-in-time)技术,也同样受类型问题困扰。
    我们将JavaScript的处理分为两个阶段,编译阶段(不同于传统编译)和执行阶段。由于不能实现判断类型,JavaScript引擎通常采用下图的做法来存储每一个对象。因为属性(相当于C++中的成员变量)没有类型,所以没办法确定其大小,而且还需要把属性名都保存下来,因为之后访问属性值都需要通过属性名匹配才能访问到。而且对象b也同样需要保存相同额属性,因为JavaScript的每个对象要自己保存这些信息,这不仅降低了性能还会带来冗余。
    在这里插入图片描述
    从获取对象属性值的具体位置的方式来看,JavaScript和C++存在以下几点差异:

    • 编译确定位置:C++在编译阶段就可以计算出对象和属性的偏移信息,方便执行阶段高效读取。而JavaScript只能在执行阶段才能确定,而且JavaScript语言能够在执行时修改对象的属性(不是修改值,而是添加或者删除属性本身)。
    • 偏移信息共享:因为C++有类型的定义,所有对象都是按照该类型来确定,并且在执行的时候不能够动态修改。所以这些对象都是共享偏移信息的,即使访问不同对象也只需要按照编译时确定的偏移量即可。而JavaScript每个对象都是自描述的,属性和位置偏移信息都包含在自身的结构中。
    • 偏移信息查找:C++利用编译时确定好的位置偏移量,可以很方便高效的查找到成员变量。JavaScript则需要利用属性名进行匹配才能查找到对应的值。

    推动JavaScript运行速度提高的另一大利器就是JIT技术,其作用是解决解释性语言的性能问题,主要思想是当解释器将源代码解释成内部表示的时候(类似于java字节码),JavaScript的执行环境不仅是解释这些内部表示,而且将其中一些字节码(使用率高的部分)转成本地代码(汇编代码),这样就可以被CPU直接执行,而不是解释执行,从而提高性能。
    下面介绍两个带来编程上便易性和模块化的概念:作用域链和闭包。
    闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因为这些变量也是该表达式的一部分。JavaScript使用作用域链来实现闭包,作用域链由执行环境维护,JavaScript中所有的标识符都是通过作用域链来查找值的。

    JavaScript 引擎

    TL;DR
    JavaScript引擎就是能够将JavaScript代码处理并执行的运行环境。
    先来看一下主流的几种语言从代码到执行的过程:

    • 首先是C/C++。该类语言就是使用编译器直接将他们编译成本地代码,用户使用的只是编译好的本地代码,能够被系统的加载器加载执行,由操作系统直接调度CPU直接执行,无须额外处理。
      在这里插入图片描述
    • Python语言。运行脚本语言通常是开发者将写好的代码直接交给用户,用户使用脚本的解释器将脚本文件加载然后解释执行。现在python也可以支持将脚本编译生成中间表示。
      在这里插入图片描述
    • Java语言。java的执行分为两个阶段,首先是像C++语言一样的编译阶段,但是java编译生成的是字节码而不是本地代码,字节码是跨平台的一种中间表示。在运行字节码阶段,Java虚拟机加载字节码,使用解释器去执行这些字节码。为了提高性能,Java虚拟机引入了JIT技术,也就是将部分字节码转变为本地代码。
      在这里插入图片描述
    • JavaScript。JavaScript现在也借鉴了java虚拟机设计的理念。他们的区别如下:
      • 类型。JavaScript无类型,所以相比Java有更大的性能损失,不过现在有一些新的技术,可以构建隐式的类型信息。
      • 对于Java来说将源代码编译成字节码和之后的执行是分开的,也就是说从源代码到抽象语法树再到字节码(相当于编译)这段时间长短对之后的执行没有影响。对于JavaScript来说,JavaScript文件下载后到执行阶段是在网页的加载和渲染过程中一块完成的,所以对于JavaScript源代码到字节码的阶段有着很高的时效性。所以对于JavaScript来说,每个阶段的时间越短越好。

    在这里插入图片描述

    JavaScript引擎通常包含以下几个部分:

    • 编译器:将源代码编译成抽象语法树,在某些引擎中还包含将抽象语法树转换成字节码。
    • 解释器:解释器主要是接收字节码,解释执行字节码,同时也依赖垃圾回收机制。
    • JIT工具:将字节码或者抽象语法树转换成本地代码
    • 垃圾回收器和分析工具:负责垃圾回收和收集引擎中的信息,帮助改善引擎的性能和功效。

    JavaScript引擎和渲染引擎

    网页的工作过程需要两个引擎,渲染引擎和JavaScript引擎。JavaScript引擎负责执行JavaScript代码,渲染引擎负责渲染网页。JavaScript引擎提供调用接口给渲染引擎,以便让渲染引擎使用JavaScript引擎来处理JavaScript代码并获取结果。JavaScript引擎需要能够访问渲染引擎构建的DOM树,所以JavaScript引擎通常需要提供桥接的接口,渲染引擎根据桥接接口来提供让JavaScript访问DOM的能力。
    渲染引擎和JavaScript引擎之间的调用关系:
    在这里插入图片描述

    两种引擎通过桥接接口来DOM结构,造成了性能的损失。所以目前为止使用JavaScript操作DOM还是一个非常低效率的事。目前主流的解决方案是使用虚拟DOM的方式。

    V8引擎


    基础

    V8的目的是提高JavaScript运行的速度。V8支持多系统、多平台。NodeJS就是基于V8打造。

    代码结构
    V8
    └─── include 		v8 接口
    │   	|
    |		|——v8.h   				包含V8的接口 
    |		|——v8-debug.h   	    调试相关接口  
    |		|——v8-profile.h     	信息收集的接口 
    |		|——v8-testing.h   		测试相关接口
    │
    └─── src			v8内部实现
    │   │   arm		arm后端,抽象语法树转成arm指令的相关代码
    │   │   ia32	ia32后端,抽象语法树转成ia32指令的相关代码
    │   │   x64		x64后端,抽象语法树转成x64指令的相关代码
    │   │   ast.h/cc		抽象语法树的实现
    │   │   d8.h/cc		一个调试程序
    │   │   full-codegen.h/cc		抽象语法树生成本地代码
    │   │   heap.h/cc		堆实现
    │   │  extensions		扩展机制
    └─── benchmarks			性能测试用例
    └─── build			编译v8项目相关脚本
    
    应用程序编程接口(API)

    在代码目录 include/V8.h 中,主要有以下这些类:

    • 各种各样的基础类:对象引用类,基本数据类型类。真正的实现在 src/objects.h/cc。
    • value:所有JavaScript数据和对象的基类
    • V8数据的句柄类:以上数据类型的对象在V8中有不同的生命周期,需要使用句柄来描述他们的生命周期,以及垃圾回收器如何使用句柄来管理这些数据,句柄类包括Local、Persistant和Handle。
    • Isolate:这个类表示一个V8引擎实例包括相关状态信息,堆等。这是一个能狗执行JavaScript代码的类。
    • Context:执行上下文,包含内置的对象和方法。
    • Extension:V8的扩展类。
    • Handle:句柄类,主要用于管理基础数据和对象,以便被垃圾回收器操作。
    • Script:用于表示被编译过的JavaScript代码。
    • HandleScope:包含一组handle的容器类,帮助一次性删除这些handle,避免重复调用。
    • FunctionTemplete:绑定C++函数到JavaScript。
    • ObjectTemplete:绑定C++对象到JavaScript。

    工作原理

    数据表示

    V8中,数据的表示分为两部分,第一部分是数据的实际内容(边长的),第二部分是数据的句柄,句柄的大小是固定的,句柄中包含指向数据的指针。这样设计的主要目的是V8需要进行垃圾回收,并需要移动这些数据内容,如果直接使用指针的话就会出问题或者需要比较大的开销,使用句柄就可以避免这些问题,只需要将句柄中的指针修改即可,使用者使用的还是句柄,它本事并没有发生变化。
    除了极少数的数据结构(整形),其他内容都是从堆中申请内存来存储他们的,因为Handle 本身就可以存储整形,同时也为了快速访问。
    JavaScript对象的实现在V8中包含3个成员,第一个是隐藏类的指针,是V8为JavaScript对象创建的隐藏类,第二个指向这个对象包含的属性值,第三个指向这个对象包含的元素。
    在这里插入图片描述

    V8工作过程

    V8的工作过程大致分为两个阶段,第一个是编译,第二个是运行。
    在这里插入图片描述
    从上图源代码到本地代码的过程,我们可以看出首先将源代码转变为抽象语法树,之后V8引擎通过JIT编译器的券代码生成器从抽象语法树直接生成本地代码,所以就没有像Java一样的虚拟机或者字节码解释器。这一点不同于JavaScriptCore引擎。这样做的原因主要是因为减少抽象语法树到字节码的转化时间,这一切都在网页加载时完成,虽然可以提高优化的可能,但是分析过程可能带来巨大的时间浪费。缺点主要包括:1. 在某些JavaScript使用场景其实使用解释器更为合适,因为没必要生成本地代码; 2. 没有中间表示会减少优化的机会,因为缺少了一个中间表示层。
    V8引擎编译JavaScript生成本地代码的过程中主要使用了以下类和过程:

    • script:表示JavaScript代码,既包含源代码,又包含生成之后的本地代码。
    • compiler:编译器类,辅助script类来编译生成代码,主要起一个协调者的作用。
    • parser:将源代码解释并构建成抽象语法树。
    • AstNode:抽象语法树节点类,是其他所有节点的基类,它包含了非常多的子类,后面会针对不同的子类生成不同的本地代码。
    • AstVistor:抽象语法树的访问者类,主要用来遍历异构的抽象语法树。
    • FullCodeGenerator:AstVistor 的子类,通过遍历抽象语法树来为JavaScript生成本地可执行的代码。

    在这里插入图片描述
    编译JavaScript代码的过程大致如下:
    Script类调用Compiler类的Compile函数为其生成本地代码。在该函数中,第一,它使用Parser类来生成抽象语法树;第二使用FullCodeGenerator类来生成本地代码。根据延迟编译思想(到运行时被调用才会编译),事实上,JavaScript中的很多函数是没有被编译生成本地代码的。因为JavaScript代码编译之前需要构建一个运行环境,所以在编译之前,V8会构建很多全局对象并加载一些内置的库(math等)。
    V8在生成本地代码之后,为了性能考虑,会通过数据分析器(Profiler)去采集一些信息,以帮助决策哪些本地代码可以进行更好的优化,这是一个逐步改进的过程。同时,如果V8发现优化后的代码性能比优化前有所降低的话,V8能够回退到之前的代码(运行阶段)。

    运行阶段主要用到的类包括:

    • script:运行代码的入口
    • Execution:运行代码的辅助类包含一些重要的函数。
    • JSFunction:需要执行的JavaScript函数表示类
    • Runtime:运行这些本地代码的辅助类,它的功能主要是提供运行时各种各样的辅助函数,包括但是不限于属性访问、类型转换、编译、算术、位操作、比较、正则表达式。
    • Heap:云顶本地代码需要使用内存堆。
    • MarkCompactCollector:垃圾回收机制的主要实现类,用来标记(Mark)、清除(Sweep)和整理(Compact)等基本的垃圾回收过程。
    • SweeperThread:负责垃圾回收的线程。

    在这里插入图片描述

    延迟编译在V8中大致思想就是在某个JavaScript函数被调用时,V8查找该函数是否有对应的本地代码,如果已经生成则直接调用,否则就会编译生成本地代码。目的是节约处理那些使用不到的代码的时间。
    V8没有中间表示层,所以很多时候代码没有很好的进行优化,为了解决这个问题,V8引入了Crankshaft 编译器,可以针对热点函数进行优化。该编译器基于源代码分析,对其中的热点函数进行优化。

    优化回滚

    前面说到的Crankshaft编译器,其实是对代码进行了比较乐观的猜测,其认为这些代码比较稳定,变量类型不会发生变化,但是JavaScript动态类型的特点使得一些变量的类型往往会发生变化。在发现变量类型发生变化了之后V8就需要进行优化回滚。
    优化回滚是一个很费时的操作,V8只有在不得不回滚的情况下才会进行回滚。所以我们平时编码过程中一定要注意不要随便改变变量的类型,或者使用flow等工具来进行JavaScript的类型检查。

    隐藏类和内嵌缓存

    V8借助C++查找变量的方式,将通过字符串匹配来查找属性值的算法改进为通过偏移位置的机制来实现,这就是隐藏类。隐藏类将对象划分为不同的组,对于组内对象拥有相同的属性名和属性值的情况,将这些属性名和对应的偏移位置保存在一个隐藏类中,组内的对象共享这个信息。
    访问对象属性的过程如下:首先获取隐藏类的地址,然后根据属性名查找偏移值,计算该属性的地址。通常可以使用内嵌缓存机制来优化上述过程,基本思想是将之前查找的隐藏类和偏移值保存下来,当下次查找的时候判断对象是否是之前的隐藏类,如果是的话,就可以直接使用缓存的偏移值,减少了查找表的时间。如果某个对象具有多个类型,会出现缓存失误的情况,一旦出现,V8会使用之前的方法。

    内存管理

    内存的划分:
    Zone类:主要是管理一系类的小块内存。如果用户需要使用一些类小内存,并且这些小内存的生命周期类似,就可以使用一个Zone对象。Zone对象首先自己申请一块内存,然后分配一些小内存,当一块小内存被分配后,就不能够被Zone回收,只能一次性回收Zone分配的所有小块内存。
    堆:V8使用堆来管理JavaScript使用的数据,生成的代码、哈希表等。为了方便回收,V8将堆分为三个部分,第一个是年轻分代,第二个是年老分代,第三个是为大对象保留的空间。
    在这里插入图片描述
    年轻分代主要是为新穿件的对象分配内存空间,因为年轻分代中的对象较容易被要求回收,为了方便垃圾回收,使用复制的方式将年轻代分为两半,一半用来分配,另一半在回收的时候负责将之前还需要保留的对象复制过来。
    老年分代则主要根据需要将年老的指针、对象、代码等数据使用的内存较少的做垃圾回收。
    大对象空间主要是用来为那些需要使用较多内存的大对象分配内存,当然同样可能包含数据和代码等分配的内存,需要注意的是每个页面只分配一个对象。

    垃圾回收:
    因为使用了分代和大数据的内存分配,V8需要使用精简整理的算法,用来标记哪些还被引用改的对象,然后消除那些没有被标记的对象,最后整理和压缩(compact)那些还需要保存的对象。垃圾回收算法还有并发标记、并发内存回收等。

    快照

    前面介绍到,V8引擎在开始启动的时候,需要加载很多内置的全局对象,同时还要建立内置的函数。为了使引擎本事更加整洁,加载对象与建立函数等任务都是使用JS文件来完成的,V8仅负责提供机制来支持,也就是在编译和执行用户自定义JavaScript代码之前,先加载他们。这些内置代码的编译和执行也是使用堆来保存执行过程中的对象、代码等,这些需要花费较多的时间,所以V8引入了快照机制。就是将这些内置的对象和函数加载之后的内存保存并序列化。序列化之后的结果很容易被反序列化,经过快照机制的启动时间,可以缩减几毫秒。
    缺点就是创建快照之后的代买没办法被Crankshaft这样的优化编译器优化,所以也存在性能上的问题。

    绑定和扩展

    有时候,JavaScript引擎所提供的能力不能满足现实的需求,比如引擎本身没有HTML5的众多能力(如地理信息),这是就需要扩展引擎的能力。
    V8提供两种扩展机制:

    • Extension机制:通过V8提供的基类Extension来达到扩展JavaScript能力的目的
    • 绑定:使用IDL文件或者接口文件来生成绑定文件,然后将这些文件同V8引擎的代码一起编译。

    JavaScriptCore 引擎


    。。。

    高效的JavaScript代码实践


    编程方式

    以下是几个值得注意的方面:

    • 类型:JavaScript的动态类型,给引擎的性能带来了重大的问题。对于函数要使用特定类型的对象或者较少的类型,以此来减少缓存失误的几率从而提高性能。对于数组,尽量使用存放相同类型的数据,这样就可以通过偏移位置来访问它们。
    • 数据表示:一些简单类型的数据可以直接保存在句柄中,这就能够有效地减少寻址时间和内存的使用。但是使用了一部分位,所以整数表示的范围会缩小,如果使用较大的整数,就需要使用堆来保存。对于数值来说,能够使用整数的,尽量不要使用浮点类型。
    • 内存:有效使用内存可以显著地提高代码的性能。对于使用垃圾回收的代码来说,简单的做法就是对引用不再使用的对象的变量设置为空(置位null)。另一个方法是通过使用 delete 关键字,来删除对象。
    • 优化回滚:不要写出触发优化回滚的代码。也就是说在执行多次之后,不要出现修改对象类型的语句。
    • 新机制:使用JavaScript引擎或者渲染引擎提供的新机制和新接口,如 requestAnimationFrame等接口,可以有效减少JavaScript引擎的额外负担。另外可以使用web worker 来提升引擎并发处理能力。
    展开全文
  • 一、总结:(1、五大浏览器、内核、js引擎;2、渲染方式) 二、详解 三、InternetExplorer: 四、Safari 五、Chrome/Chromium 六、Opera 七、Firefox 其它js引擎: 一、总结: 1、主流浏览器内核及其js引擎...

    目录

     

    一、总结:(1、五大浏览器、内核、js引擎;2、渲染方式)

    二、详解

    三、Internet Explorer: 

    四、Safari

    五、Chrome / Chromium

    六、Opera

    七、Firefox

    其它js引擎:


    一、总结:

    1、主流浏览器内核及其js引擎

    浏览器内核js引擎
    IETrident内核JScript
    Firefox(火狐)Gecko内核,俗称Firefox内核

    FireFox3.0及其以下:SpiderMonkey

    FireFox3.1及其以上:TraceMonkey

    Google Chrome(谷歌)Chromium内核或Chrome内核,以前是Webkit内核,现在是Blink内核V8
    Safari(苹果)Webkit内核;

    Safari3.1及其以下:JavaScriptCore,

    safari4.0:SquirrelFish

    Opera(欧朋) 最初是自己的Presto内核,后来是Webkit,现在是Blink内核; opera9.5及其以上:Futhark

    其他: 

    1. 360浏览器、猎豹浏览器内核:IE+Chrome双内核; 
    2. 搜狗、遨游、QQ浏览器内核:Trident(兼容模式)+Webkit(高速模式); 
    3. 百度浏览器、世界之窗内核:IE内核; 
    4. 2345浏览器内核:以前是IE内核,现在也是IE+Chrome双内核;

    2、浏览器如何渲染页面

    第一步.DOM构造
            $.HTML解析出DOM树(DOM Tree):
                浏览器首先将收到的HTML代码,通过html解析器解析构建一颗DOM树(DOM Tree)
            $.CSS解析出样式表规则(Style Rules),也叫做CSSOM(CSS Object Model)
                浏览器将接受到的css代码,通过css解析器构建出样式表规则(Style Rules)
            $.将二者关联生成渲染树(Render Tree)
                将这些规则分别放到对应的DOM树节点上,得到一颗渲染树(Render Tree)---带有样式属性的DOM树
    第二步.布局
            浏览器按从上到下,从左到右的顺序,计算和读取Render Tree每个节点信息。将树上的节点压入文档流然后布局。
    第三步.绘制页面
            Painting 根据计算好的信息绘制整个页面 

    二、详解

    所谓的“浏览器内核”无非指的是一个浏览器最核心的部分——“Rendering Engine”,直译这个词汇叫做“渲染引擎”,不过我们也常称其为“排版引擎”、“解释引擎”。这个引擎的作用是帮助浏览器来渲染网页的内容,将页面内容和排版代码转换为用户所见的视图。

     

    注:有时候我们所说的“浏览器内核”甚至“渲染引擎”,其实除了渲染引擎,也悄悄包含了javascript引擎,如WebKit,它由渲染引擎WebCore和javascript引擎JSCore组成。

            不同的内核对网页编写语法的解释也有不同,进而导致同一个页面在不同内核的浏览器下显示出来的效果也会有所出入,这也是前端工程师需要让作品兼容各种浏览器的原因。

            我们常常喜欢把浏览器内核与某浏览器名称直接挂钩起来,如IE内核、Chrome内核,其实是不全面的说法。比如Opera在7.0版本到12.16版本中采用的是独立研发的Presto引擎,但在后续跟随了Chrome的脚步加入了WebKit大本营,放弃了Presto;另外即使名称相同,但版本不同的引擎也可能存在较大差别。比如IE6使用的是Trident早期版本,存在许多bug,性能也较低。而最新的IE11所使用的Trident7.0版本已经可以支持WebGL(3D绘图标准)以及HTML5大部分标准。

            下面按照各个主流浏览器,介绍下它们所使用的浏览器内核的历程。

    三、Internet Explorer: 

    1、简介

    它采用的排版引擎(俗称内核)为Trident。

    2、js引擎

    Chakra:中文译名为查克拉,用于Internet Explorer 9的32位版本及IE10+。

    四、Safari

    1、简介

     Safari是苹果公司开发的浏览器,使用了KDE(Linux桌面系统)的KHTML作为浏览器的运算核心,Safari所用浏览器内核的名称是大名鼎鼎的WebKit。

    需要了解的是,虽然我们称WebKit为浏览器内核(或浏览器引擎),但不太适合直接称之为我们开头提到的Rendering Engine(渲染引擎),因为WebKit本身主要是由两个引擎构成的,一个正是渲染引擎“WebCore”,另一个则是javascript解释引擎“JSCore”,它们均是从KDE的渲染引擎KHTML及javascript解释引擎KJS衍生而来。

            在2010年4月,苹果公司宣布了其浏览器引擎Webkit的最新项目 Webkit2。Webkit2的目标是实现独立进程与非阻断式API。

    2、js引擎
     

    五、Chrome / Chromium

    1、简介

    谷歌Chrome/Chromium浏览器从08年创始至今一直使用苹果公司的WebKit作为浏览器内核原型,是WebKit的一个分支,我们可以称之为Chromium引擎(注意我们这里说的是Chromium引擎,而不是Chromium浏览器)。

    chrome和Chromium两个浏览器的区别:

    Chromium浏览器是谷歌为发展自家的浏览器Chrome而开启的计划,所以Chromium相当于Chrome的工程版或称实验版,新功能会率先在Chromium上实现,待验证后才会应用在Chrome上。

    Chrome总共有四个更新分支:Canary、Dev、Beta、Stable,稳定性依次增强。

    13年发布的Chrome 28.0.1469.0版本开始,Chrome放弃Chromium引擎转而使用最新的Blink引擎(基于WebKit2——苹果公司于2010年推出的新的WebKit引擎),Blink对比上一代的引擎精简了代码、改善了DOM框架,也提升了安全性。

    2、js引擎

    V8:开源,由Google丹麦开发,是Google Chrome的一部分。

    注:我们上面提到Chrome是基于WebKit的分支,而WebKit又由渲染引擎“WebCore”和JS解释引擎“JSCore”组成,可能会让你搞不清V8和JSCore的关系。你可以这样理解——WebKit是一块主板,JSCore是一块可拆卸的内存条,谷歌实际上认为Webkit中的JSCore不够好,才自己搞了一个V8 JS引擎,这就是Chrome比Safari在某些JS测试中效率更高的原因。

    六、Opera

    1、简介

      Opera浏览器,是一款挪威Opera Software ASA公司制作的支持多页面标签式浏览的网络浏览器。是跨平台浏览器可以在Windows、Mac和Linux三个操作系统平台上运行。

    Opera在2013年2月宣布放弃Presto,转而跟随Chrome使用WebKit分支的Chromium引擎作为自家浏览器核心引擎。

            在Chrome与2013年推出Blink引擎(也是基于WebKit的分支)之后,Opera也紧跟其脚步表示将转而使用Blink作为浏览器核心引擎。

    2、js引擎

    • Linear A:用于Opera 4.0~6.1版本。
    • Linear B:用于Opera 7.0~9.2版本。
    • Futhark:用于Opera 9.5~10.2版本。
    • Carakan:由Opera软件公司编写,自Opera10.50版本开始使用。

    七、Firefox

    1、简介

    ozilla Firefox是一个开源网页浏览器,原名是Firebird,2004年2月9日,Mozilla Firebird决定改称Mozilla Firefox。

    2、js引擎

    • SpiderMonkey:第一款JavaScript引擎,由Brendan Eich在Netscape Communications时编写,用于Mozilla Firefox 1.0~3.0版本。
    • Rhino:由Mozilla基金会管理,开放源代码,完全以Java编写。
    • TraceMonkey:基于实时编译的引擎,其中部份代码取自Tamarin引擎,用于Mozilla Firefox 3.5~3.6版本。
    • JaegerMonkey:德文Jäger原意为猎人,结合追踪和组合码技术大幅提高性能,部分技术借凿了V8、JavaScriptCore、WebKit:用于Mozilla Firefox 4.0以上版本。
    • IonMonkey:可以对JavaScript编译后的结果进行优化,用于Mozilla Firefox 18.0以上版本。
    • OdinMonkey:可以对asm.js进行优化,用于Mozilla Firefox 22.0以上版本。

    其它js引擎:

    KJS:KDE的ECMAScript/JavaScript引擎,最初由Harri Porten开发,用于KDE项目的Konqueror网页浏览器中。

    Narcissus:开放源代码,由Brendan Eich编写(他也参与编写了第一个SpiderMonkey)。

    Tamarin:由Adobe Labs编写,Flash Player 9所使用的引擎。

    Nitro(原名SquirrelFish):为Safari 4编写。

     

     

     

     

    展开全文
  • java js引擎调试js代码

    2018-03-14 11:30:03
    java js引擎调试js代码,java js引擎调试js代码,java js引擎调试js代码,java js引擎调试js代码
  • 浏览器内核-渲染引擎js引擎

    千次阅读 2017-11-05 23:16:54
    一个完整的浏览器包含浏览器内核、界面框架和其它的功能支撑。浏览器内核分成两部分:渲染引擎js引擎
  • 最新版Google V8引擎库,谷歌Chrome JavaScript引擎,VS2013 32位编译,可正式使用
  • 过去,一些Minecraft插件以前使用Nashorn JS引擎来评估一些东西。 Java 15中已删除了此引擎,这给这些插件造成了一些问题。 NashornJS插件提供了一个ScriptEngineManager来创建新的脚本引擎。 它是如何工作的? ...
  • NULL 博文链接:https://andilyliao.iteye.com/blog/722249
  • V8 JS引擎

    千次阅读 2018-05-15 20:59:20
    Google开发V8Google (丹麦)研发小组在 2006 年开始研发 V8 ,部分的原因是 Google 对既有 JavaScript 引擎的执行速度不满意, 在2008年推出chrome, 巨大的速度优势, 迅速占领市场. 2017年chrome的市场...
  • 目前浏览器都是在UI线程解析js,以火狐浏览器为例,我重新编译了js引擎,并且在js引警中添加了sleep方法,该方法调用c语言的线程睡眠函数. 将方法附加到Object上,方法签名为sleep();无参数.默认休眠1秒钟,如果你在js中...
  • 博文iOS——为你的项目引入超轻量级JS引擎JSPatch中的代码 博文地址:http://blog.csdn.net/u010127917/article/details/50531356
  • JavaScript引擎运行原理解析

    千次阅读 2018-09-30 10:16:41
    1. 什么是JavaScript解析引擎?... 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2。 “JavaScript 引擎”通常被称作一种虚拟机。 JavaScript 虚拟机是一种进程虚拟...
  • JerryScript:用于物联网JavaScript引擎JerryScript是用于资源受限设备(例如微控制器)的轻量级JavaScript引擎。 它可以在RAM少于64 KB的设备上运行,并且可以运行以下应用程序:JerryScript:物联网JavaScript引擎...
  • 什么是 JavaScript 引擎

    千次阅读 2018-07-05 01:12:29
    什么是 JavaScript 引擎 简单来讲,就是能够将 Javascript ...当然为了提高 js 的执行速度,同时随着 JIT (Just In Time)的技术引入,现在的 js 引擎大多会做一些性能优化,就是在执行前会将抽象语法树再转成一...
  • JS引擎理解并优化javascript代码

    千次阅读 2019-06-17 18:43:45
    序言:作为一名前端工程师,对于javascript大家都不陌生,这篇文章从更深层次的方向——JS引擎去理解javascript到底是怎么运行的,从而进行优化。 JS Engine—— JS 引擎介绍 一、基本介绍 js引擎是一个专门运行...
  • V9 JavaScript 引擎 V9 是使用 flex 和 bison 用 C++ 编写的基本 JavaScript 引擎。 安装 下载或克隆源代码并在其中运行make 。 flex和bison是必需的。 将创建一个名为v9的可执行文件。 跑步 REPL 尚不可用,因此...
  • ChakraCore 是微软开源的 Microsoft Edge 浏览器 Chakra JavaScript 引擎的核心部分,主要用于 Microsoft Edge 和 Windows 中 HTML/CSS/JavaScript 编写的应用。ChakraCore 支持 x86/x64/ARM 架构 JavaScript 的 ...
  • jsjs 是在 Java 虚拟机之上用 JavaScript 编写的 JavaScript 编译器 + 引擎 如何构建它? 首先,您需要一个与 Java 8 兼容的 JDK,然后您必须编辑脚本 run_build.js 中定义 JDK 位置的行 var java_home = "PATH_...
  • 作为异步事件驱动JavaScript运行时,Node.js旨在构建可扩展的网络应用程序
  • JavaScript引擎工作原理

    2017-11-25 23:11:11
    JavaScript引擎工作原理 JavaScript引擎工作原理 JavaScript引擎工作原理
  • SophonJS 是嵌入式 javascript 引擎。特点:ECMAScript5 标准占用空间小 将源代码编译为字节码指令指令文件存储和读取功能 标签:SophonJS
  • 微软宣布将开源 Microsoft Edge 和 IE 所用的 JavaScript 引擎 Chakra 的核心组件,并以 ChakraCore 名称开源。github网址:https://github.com/Microsoft/ChakraCore。使用方法参考:...
  • 浏览器内核又可以分成两部分:渲染引擎(layout engineer或者RenderingEngine)和JS引擎。 渲染引擎功能作用  渲染引擎,负责对网页语法的解释(如HTML、JavaScript)并渲染网页。所以,通常所谓的浏览器内核也就是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 317,676
精华内容 127,070
关键字:

js引擎