标题:使用 Google V8 引擎开发可定制的应用程序 出处:刘新修 时间:Thu, 02 Mar 2017 10:20:49 +0000 作者:刘新修 地址:http://liuxinxiu.com:80/V8/ 内容: V8 引擎概览 Google V8 引擎使用 C++ 代码编写,实现了 ECMAScript 规范的第五版,可以运行在所有的主流 操作系统中,甚至可以运行在移动终端 ( 基于 ARM 的处理器,如 HTC G7 等 )。V8 最早被开发用以嵌入到 Google 的开源浏览器 Chrome 中,但是 V8 是一个可以独立的模块,完全可以嵌入您自己的应用,著名的 Node.js( 一个异步的服务器框架,可以在服务端使用 JavaScript 写出搞笑的网络服务器 ) 就是基于 V8 引擎的。 和其他 JavaScript 引擎一样,V8 会编译 / 执行 JavaScript 代码,管理内存,负责垃圾回收,与宿主语言的交互等。V8 的垃圾回收器采用了众多技术,使得其运行效率大大提高。通过暴露宿主对象 ( 变量,函数等 ) 到 JavaScript,JavaScript 可以访问宿主环境中的对象,并在脚本中完成对宿主对象的操作。 V8 引擎基本概念 图 1. V8 引擎基本概念关系图 ( 根据 Google V8 官方文档 ) handle handle 是指向对象的指针,在 V8 中,所有的对象都通过 handle 来引用,handle 主要用于 V8 的垃圾回收机制。 在 V8 中,handle 分为两种:持久化 (Persistent)handle 和本地 (Local)handle,持久化 handle 存放在堆上,而本地 handle 存放在栈上。这个与 C/C++ 中的堆和栈的意义相同 ( 简而言之,堆上的空间需要开发人员自己申请,使用完成之后显式的释放;而栈上的为自动变量,在退出函数 / 方法之后自动被释放 )。持久化 handle 与本地 handle 都是 Handle 的子类。在 V8 中,所有数据访问均需要通过 handle。需要注意的是,使用持久化 handle 之后,需要显式的调用 Dispose() 来通知垃圾回收机制。 作用域 (scope) scope 是 handle 的集合,可以包含若干个 handle,这样就无需将每个 handle 逐次释放,而是直接释放整个 scope。 在使用本地 handle 时,需要声明一个 HandleScope 的实例,scope 是 handle 的容器,使用 scope,则无需依次释放 handle。 HandleScope handle_scope; Local temp; 上下文 (context) context 是一个执行器环境,使用 context 可以将相互分离的 JavaScript 脚本在同一个 V8 实例中运行,而互不干涉。在运行 JavaScript 脚本是,需要显式的指定 context 对象。 数据及模板 由于 C++ 原生数据类型与 JavaScript 中数据类型有很大差异,因此 V8 提供了 Data 类,从 JavaScript 到 C++,从 C++ 到 JavaScrpt 都会用到这个类及其子类,比如: Handle Add(const Arguments& args){ int a = args[0]->Uint32Value(); int b = args[1]->Uint32Value(); return Integer::New(a+b); } Integer 即为 Data 的一个子类。 V8 中,有两个模板 (Template) 类 ( 并非 C++ 中的模板类 ):对象模板 (ObjectTempalte) 和函数模板 (FunctionTemplate),这两个模板类用以定义 JavaScript 对象和 JavaScript 函数。我们在后续的小节部分将会接触到模板类的实例。通过使用 ObjectTemplate,可以将 C++ 中的对象暴露给脚本环境,类似的,FunctionTemplate 用以将 C++ 函数暴露给脚本环境,以供脚本使用。 初始化 context 是使用 V8 引擎所必需的过程,代码非常简单: Persistent context = Context::New(); V8 引擎使用示例 有了上面所述的基本概念之后,我们来看一下一个使用 V8 引擎的应用程序的基本流程: 创建 HandleScope 实例 创建一个持久化的 Context 进入 Context 创建脚本字符串 创建 Script 对象,通过 Script::Compile() 执行脚本对象的 Run 方法 获取 / 处理结果 显式的调用 Context 的 Dispose 方法 基本代码模板 清单 1. 代码模块 #include using namespace v8; int main(int argc, char *argv[]) { // 创建一个句柄作用域 ( 在栈上 ) HandleScope handle_scope; // 创建一个新的上下文对象 Persistent context = Context::New(); // 进入上一步创建的上下文,用于编译执行 helloworld Context::Scope context_scope(context); // 创建一个字符串对象,值为'Hello, Wrold!', 字符串对象被 JS 引擎 // 求值后,结果为'Hello, World!' Handle source = String::New("'Hello' + ', World!'"); // 编译字符串对象为脚本对象 Handle