Google Javascript脚本引擎v8学习笔记_第1页
Google Javascript脚本引擎v8学习笔记_第2页
Google Javascript脚本引擎v8学习笔记_第3页
Google Javascript脚本引擎v8学习笔记_第4页
Google Javascript脚本引擎v8学习笔记_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Google Javascript 脚本引擎 v8 学习笔记目录一、Google v8 整体印象 .21.1 Google v8 是什么, 能做什么? .21.2 Google v8 的获取及编译 21.2.1 获取源码 21.2.2 编译类库及示例 3二、Google v8 入门 32.1 v8 的基本概念 32.2 从 HelloWorld 开始 .52.3 在 C+中访问 Javascript 的变量及函数 .52.4 在 Javascript 中访问 C+全局函数及变量 92.5 在 C+中“声明”“Javascript 类”, 供 Javascript 实例化 .152.6 封装完整的 C+类到 Javascript 中,供 Javascript 实例化 .16三、Google v8 的开源应用 163.1 Node.js.163.2 v8cgi.17四、参考资料 .17五、本文源码 .18一、Google v8 整体印象1.1 Google v8 是什么 ,能做什么?v8 是一款 Javascript 脚本引擎,它开放源代码,由 Google 丹麦开发,是 Google Chrome 的一部分。和其它脚本语言(php,lua,python 等)一样,Javascript 也可以内嵌于应用程序,和编译性语言(c/c+ 等)交互。由于 v8 是用 C+写的,所以在 C+中使用 javascript 显得更加的自然。通过在应用程序中引入脚本解析器,将一些业务逻辑交由脚本实现,可以使得系统更加灵活。C/C+的高效,Javascript 的灵巧多变,使得我们的应用程序可以兼顾性能和效率。说得再具体直白一点,就是我们可以通过编写 javascript 脚本来操作 C+提供的类,可以编写 javascript 函数供 C+调用。像下面这样写 javascript 一定非常爽吧?var socket = new Socket(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP);socket.setOption(Socket.SO_REUSEADDR, true);var conn = socket.connect(““, 80);if (conn)var httpHeader = “GET /pansunyou HTTP/1.1rnHost: rnrn“; socket.send(httpHeader);var responseText = socket.receive(12000);printf(“responseText=“+responseText+“nn“);socket.close();至于其性能,好吧,算我迷信,Google 出品一定差不到哪里去。再是我也未完全明白它的原理,就不抄网上的文字了,可以本文的参考资料看到相关的介绍文档。1.2 Google v8 的获取及编译1.2.1 获取源码Google v8 以源码的形式提供,其开源项目地址为:/p/v8/ 在 linux 下,可以使用以下命令获取其源码:svn checkout /svn/trunk/ v8在 windows 下,可以 TortoiseSVN 导出源码:1.2.2 编译类库及示例Google V8 的编译需要使用 Scons(大概类似于 Makefile 或者 CMake 之类),而 Scons 需要使用 Python2.x,所以需要先安装这两玩意儿。 记得 python 一定要是 2.x 系列的,否则灰常灰常的郁闷。//Windows 平台,进入命令后先运行,以初始化 vc 编译环境。cmd /k “C:Program FilesMicrosoft Visual Studio 9.0VCvcvarsall.bat“ x86进入 v8 源码目录,执行 Scons -help 可查看编译选项。因为我是用来学习的,所以我编译 debug 版本,并且选择打印尽可能多的消息。在 windows 下,尽量选择编译为动态库吧,在为静态的 v8.lib 有 160MB 之巨,一个 helloworld 程序都要链接个半天。我的编译选项:scons mode=debug verbose=on library=shared msvcrt=static编译结果为同目录下的 v8_g.lib 和 v8_g.dll,release 编译时无_g 后缀。使用时非常简单,只需要在 vc 工程中加入 v8 的 include 目录,链接加入 v8_g.lib 即可。二、Google v8 入门2.1 v8 的基本概念在使用 v8 引擎之前,先来了解一下几个基本概念:句柄(handle) ,作用域(scope ) ,上下文环境(可以简单地理解为运行环境) 。2.1.1 句柄( Handle)从实质上来说,每一个句柄就是一个指向 v8 对象的指针,所有的 v8 对象必须使用句柄来操作。这是先决条件,如果一个 v8 对象没有任何句柄与之相关联,那么这个对象很快就会被垃圾回收器给干掉(句柄跟对象的引用计数有很大关系) 。在 v8.h 中,我们可以看到几个相关的类( 模板?) :Handle、Local、Persistent,使用时大致为:Handle ft0 = FunctionTemplate:New();Local ft1 = Local:New(FunctionTemplate:New();Persistent ft3= Persistent:New(FunctionTemplate:New();它们其实没有太大的差别,只是作用域不一样,Handle 和 Local 一样会在 C+的作用域中被同域的 HandleScope(后面再解释)释放掉。而 Persistent 则相当于是永久性的实例,它所持有 javascript 对象只有调用 Despose()的时候再会显示释放。2.1.2 作用域( Scope)从概念上理解,作用域可以看成是一个句柄的容器,在一个作用域里面可以有很多很多个句柄(也就是说,一个 scope 里面可以包含很多很多个 v8 引擎相关的对象) ,句柄指向的对象是可以一个一个单独地释放的,但是很多时候(真正开始写业务代码的时候) ,一个一个地释放句柄过于繁琐,取而代之的是,可以释放一个 scope,那么包含在这个 scope中的所有 handle 就都会被统一释放掉了。Scope 在 v8.h 中有这么几个: HandleScope,Context:Scope。HandleScope 是用来管理Handle 的,而 Context:Scope 仅仅用来管理 Context 对象。代码像下面这样:/在此函数中的 Handle 都会被 handleScope 管理HandleScope handleScope;/创建一个 js 执行环境 ContextHandle context = Context:New();Context:Scope contextScope(context);/其它代码一般情况下,函数的开始部分都放一个 HandleScope,这样此函数中的 Handle 就不需要再理会了释放资源了。而 Context:Scope 仅仅做了:在构造中调用 context-Enter(),而在析构函数中调用 context-Leave()。2.1.3 上下文环境( Context)从概念上讲,这个上下文环境也可以理解为运行环境。在执行 javascript 脚本的时候,总要有一些环境变量或者全局函数。我们如果要在自己的 c+代码中嵌入 v8 引擎,自然希望提供一些 c+编写的函数或者模块,让其他用户从脚本中直接调用,这样才会体现出javascript 的强大。我们可以用 c+编写全局函数或者类,让其他人通过 javascript 进行调用,这样,就无形中扩展了 javascript 的功能。Context 可以嵌套,即当前函数有一个 Context,调用其它函数时如果又有一个Context,则在被调用的函数中 javascript 是以最近的 Context 为准的,当退出这个函数时,又恢复到了原来的 Context。我们可以往不同的 Context 里 “导入”不同的全局变量及函数,互不影响。据说设计Context 的最初目的是为了让浏览器在解析 HTML 的 iframe 时,让每个 iframe 都有独立的javascript 执行环境,即一个 iframe 对应一个 Context。2.1.4 零散的应该预先了解的知识2.2 从 HelloWorld 开始算了,HelloWorld 没啥意思,就不写了。/intl/zh-CN/apis/v8/get_started.html2.3 在 C+中访问 Javascript 的变量及函数从 Context 的概念可知,无论何时我们运行 javascript 脚本,或者执行 C+的某行代码,我们都处在当前 Context(可以通过 Context:GetCurrent()获取)中,即当前一定有一个javascript 运行环境。在“当前运行环境”中存在一个全局对象,是 GetCurrent()-Global(),里面的东西就是我们执行 javascript 脚本时可以访问的或者可以修改的全局数据。所以,要在 C+中访问 Javascript 脚本中的数据,就是先去执行这段 javascript 代码,让它去初始化或者修改或者填充 Context:GetCurrent()-Global()对象,在这之后,我们就可以通过 Global()对象的 Get 函数来提取其中的内容了,包括:全局变量,全局函数。访问的步骤大致如下:/从全局对象中取出需要的内容Handle tmpVal = globalObj-Get(String:New(“javascript 中的全局变量名/函数名“);/根据不同的类型做判断tmpVal. IsEmpty(); / IsFunction(); / context = Context:New();Context:Scope contextScope(context);/javascript 中无打印函数Handle globalObj = Context:GetCurrent()-Global();globalObj-Set(String:New(“printf“), FunctionTemplate:New(_printfForJS)-GetFunction();string scriptFileText = tk:getFileContents(argv1);if (scriptFileText.length() scriptSource = String:New(scriptFileText.c_str();/“编译 “脚本TryCatch catcher;Handle script = Script:Compile(scriptSource);if (catcher.HasCaught() tk:printError(return 0;/执行脚本 Handle result = script-Run();if (catcher.HasCaught() tk:printError(return 0;/Run()之后便可以访问 script 中的变量及函数了/1. 访问全局 String 变量 globalStrHandle _globalStr = globalObj-Get(String:New(“globalStr“);if (_globalStr.IsEmpty()printf(“脚本中无 globalStr 变量!n“);else printf(“globalStr=%sn“, *String:Utf8Value(_globalStr);/2. 全局整型变量 globalIntHandle _globalInt = globalObj-Get(String:New(“globalInt“);if (_globalInt.IsEmpty()printf(“脚本中无 globalInt 变量!n“);else printf(“globalInt=%dn“, _globalInt-ToInt32()-Value();/3. 调用全局函数 globalFunctionHandle _globalFunction = globalObj-Get(String:New(“globalFunction“);if (_globalFunction.IsEmpty()|!_globalFunction-IsFunction()printf(“脚本中无 globalFunction 函数!n“ );else Local v1 = Int32:New(123);Local v2 = Int32:New(456);Handle func = Handle:Cast(_globalFunction);Handle args2 = v1, v2 ;Handle tmpCallVal = func-Call(globalObj, 2, args);if (tmpCallVal-IsInt32()printf(“globalFunction(%d,%d)=%dn“, v1-ToInt32()-Value(), v2-ToInt32()-Value(), tmpCallVal-ToInt32()-Value();else printf(“Error: globalFunction 返回的应该是 int 才对.n“ );/4. 访问全局对象 ConfigHandle _Config = globalObj-Get(String:New(“Config“);if (_Config.IsEmpty()printf(“脚本中无 Config 变量!n“ );else if (_Config-IsObject()/4.1 对象中的成员变量 Config.testStringHandle _testString = Handle:Cast(_Config)-Get(String:New(“testString“);if (!_testString.IsEmpty()printf(“Config.testString=%sn“, *String:Utf8Value(_testString);/4.2 对象中的函数 Config.testFuncHandle _testFunc = Handle:Cast(_Config)-Get(String:New(“testFunc“);if (!_testFunc-IsFunction()printf(“Config 中无_testFunc 函数!n“);else Handle ConfigTestFun = Handle:Cast(_testFunc);Handle args = String:New(“callJavascriptFunctionFromCppn“);ConfigTestFun-Call(globalObj,1,args);return 0;2.4 在 Javascript 中访问 C+全局函数及变量V8 是 javascript 引擎,凡 javascript 中有的概念,都有 C+相对应的类或者模板类与之对应。Javascript 中无非就是 function,object,String,Array,Date,Number 这些,与之对应的 C+类有 Function/FunctionTemplate、Object/ObjectTemplate、String、Array 、Date 等。我们知道当我们通过 Script 的 Run 去执行 javascript 代码时,我们的代码相当于处在一个全局对象内:Context:GetCurrent()-Global(),所以我们要让 javascript 访问到我们在 C+中捏造出的东西,只要向 Global()对象注册各种数据即可,调用函数为 Set。测试用的 js 脚本 fromJavaScriptToCpp.jsvar test = dumpArray:function()printf(“fromJavaScriptToCpp:dumpArrayn“);/测试访问全局变量 testArrayvar _type = typeof(testArray);var len = testArray.length;printf(“testArray.length=“+len+“n“);printf(“typeof(testArray)=“+_type+“n“);testArray.push(“another string.“);printf(“printf(testArray.join(|)=“+testArray.join(“|“);printf(“nn“);,dumpObject:function()printf(“fromJavaScriptToCpp:dumpObjectn“);/测试访问全局变量 testObjectprintf(“testObject.strVal=“+testObject.strVal+“n“);printf(“n“);,testSocket:function()printf(“fromJavaScriptToCpp:testSocketn“);/将 socket 移植到 javascript 中var socket = new Socket(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP);socket.setOption(Socket.SO_REUSEADDR, true);var conn = socket.connect(““, 80);if (conn)//pansunyouvar httpHeader = “GET /pansunyou HTTP/1.1rnHost: rnrn“; socket.send(httpHeader);var responseText = socket.receive(12000);printf(“responseText=“+responseText+“nn“);socket.close();,testTestObj:function()printf(“fromJavaScriptToCpp:testTestObjn“);var obj = new TestObj;obj.printName();obj.setName(“pan“);obj.printName();obj.setName(“pansun“);obj.printName();obj.setName(“pansunyou“);obj.printName();obj.dispose();printf(“fromJavaScriptToCpp.jsn“);test.dumpArray();test.dumpObject();/test.testSocket();test.testTestObj();C+代码 fromJavaScriptToCpp.cpp:/仅供测试class CTestObj public:CTestObj()printf(“CTestObj:CTestObjn“);buffer = (char*)malloc(1024*1024);CTestObj()printf(“CTestObj:CTestObjn“);if(buffer)free(buffer);buffer = NULL;void printfName()printf(“CTestObj:printfName name=%sn“, name.c_str();void setName(const char*xname)name = xname;string name;char *buffer;/此函数用来做为 TestObj 的 “构造函数 “/在 var obj = new TestObj; 的时候调用JS_METHOD(_testObjConstructor)ASSERT_CONSTRUCTOR;SAVE_PTR(0, new CTestObj();return args.This();/只是个包装JS_METHOD(_testObjPrintName)CTestObj *pObj = LOAD_PTR(0, CTestObj *);if(pObj!=NULL)pObj-printfName();return args.This();/只是个包装JS_METHOD(_testObjSetName)CTestObj *pObj = LOAD_PTR(0, CTestObj *);if(pObj!=NULL)String:AsciiValue xname(args0);pObj-setName(*xname);return args.This();/用来显式地释放内部数据/obj.dispose();JS_METHOD(_testObjDispose)CTestObj *pObj = LOAD_PTR(0, CTestObj *);if(pObj!=NULL)delete pObj;pObj = NULL;SAVE_PTR(0, pObj);return args.This();/ / brief 在 javascript 环境中构造一个 class TestObj/ / confused v8 的垃圾回收机制还没弄明白 , 这里的 TestObj 必须显式释放 : obj.dispose();/Handle pubishCppClass_TestObj()v8:HandleScope handle_scope;/指定 “构造函数 “v8:Handle ft = v8:FunctionTemplate:New(_testObjConstructor);ft-SetClassName(JS_STR(“TestObj“);/在 javascript 的 class 内放一个 C+实例 , *CTestObj/所以要设定 InternalFieldCount 为 1v8:Handle it = ft-InstanceTemplate();it-SetInternalFieldCount(1); /* *CTestObj */类的 “成员函数 “v8:Handle pt = ft-PrototypeTemplate();pt-Set(“printName“, v8:FunctionTemplate:New(_testObjPrintName);pt-Set(“setName“, v8:FunctionTemplate:New(_testObjSetName);/用来释放内部数据 .pt-Set(“dispose“, v8:FunctionTemplate:New(_testObjDispose);return handle_scope.Close(ft);extern Handle pubishJavascriptClass_Socket();/ / brief 学习如何在 javascript 中访问 c+中的变量及函数/ param argv1 演示用的 jsint fromJavaScriptToCpp(int argc, char*argv)if (argc!=2)printf(“参数错误! x.exe fromJavaScriptToCpp.jsn“);return 0;HandleScope handleScope;Handle context = Context:New();Context:Scope contextScope(context);/javascript 中无打印函数Handle globalObj = Context:GetCurrent()-Global();globalObj-Set(String:New(“printf“), FunctionTemplate:New(_printfForJS)-GetFunction();string scriptFileText = tk:getFileContents(argv1);if (scriptFileText.length() _array = Array:New();char *strList = “hello“,“the“, “world“;for (int i=0; iSet(JS_INT(i), JS_STR(strListi);globalObj-Set(String:New(“testArray“), _array);/2. 创建一个 Object testObjectHandle _obj = Object:New();_obj-Set(JS_STR(“strVal“), JS_STR(“Hi,this is strVal“);globalObj-Set(String:New(“testObject“), _obj);/3. 创建一个可以在 javascript 中 New 的 class.(怎么表述 ?)Handle bb = pubishJavascriptClass_Socket();globalObj-Set(String:New(“Socket“), bb-GetFunction();/4. 包装一个含有真正 C+类实体的 javascript class/confused v8 的垃圾回收机制还没弄明白 , 这里的 TestObj 必须显式释放 : obj.dispose();Handle cc = pubishCppClass_TestObj();globalObj-Set(String:New(“TestObj“), cc-GetFunction();/还有其它一些东西 ,比如 SetAccessor/有空再研究/globalObj-SetAccessor()/最后,环境准备好后,可以执行脚本了 .Handle scriptSource = String:New(scriptFileText.c_str();/“编译 “脚本TryCatch catcher;Handle script = Script:Compile(scriptSource);if (catcher.HasCaught() tk:printError(return 0;/执行脚本 Handle result = script-Run();if (catcher.HasCaught() tk:printError(return 0;/confused 这样清理有用么 ?v8:Handle keys = JS_GLOBAL-GetPropertyNames();int length = keys-Length();for (int i=0;i key = keys-Get(JS_INT(i)-ToString();JS_GLOBAL-ForceDelete(key);return 0;2.5 在 C+中“声明”“Javascript 类”, 供 Javascript 实例化其实 2.4 中已经在使用了,这里单独总结一下。我的初衷是想能够像这样写 javascript 代码:var obj = new CSomeClass(1,”参数 2”);obj-doAction1();obj-doAction2();obj-release();从 javascript 语言出发,这里的 CSomeClass 其实只是个 function,因为 javascript 中并没有真实的 class。如果是由 javascript 来实现 CSomeClass,可能是像这样:var CSomeClass = function(param1, parm2)CSomeCperty.doAction1 = function()事实上,就算换成用 C+(V8 类库)来完成这个 CSomeClass,也是同样的思路。以上实现,V8 里面有一一对应的内容。类 FunctionTemplate,函数模板,是用来产生 Function,即它的 GetFunction()函数。FunctionTemplate 有个 InstanceTemplate()函数,返回一个 ObjectTemplate,通过它 V8允许我们设定当前这个 FunctionTemplate 可以内置多少个值(即 C/C+的数据类型) 。比如当我们封装 Socket 类时,我们需要保存 SOCKET、端口等变量,其实这更像是“类的成员变量” 。FunctionTemplate 有个 PrototypeTemplate 函数,同样返回类型为 ObjectTemplate 的对象,这即是此函数模板产生的 Function 的 property 操作者。通过它我们可以指定将来产生的 Function 会有哪些 property,这非常像指定“类的成员函数” 。有了这些知识,再看下面的代码可能就要觉得自然多了。/第一步:生成一个 FunctionTemplate,同时指定“构造函数“/这个“构造函数”在 var obj = CSomeClass(xxx);的时候被调用v8:Handle ft = v8:FunctionTemplate:New(_testObjConstructor);ft-SetClassName(JS_STR(“CSomeClass“); / it = ft-InstanceTemplate();it-SetInternalFieldCount(1); /第三步:指定类的“成员函数“/其实这些 FunctionTempalte:New()中包含的都是全局函数,他们的参数都是一模一样的/都是 Const Argumentspt-Set(“doAction1“, v8:FunctionTemplate:New(_doaction1);/第四步:将 CSomeClass 塞到全局环境中,或者其它对象中global-Set(String:New(“CSomeClass”, fp-GetFunction();2.6 封装完整的 C+类到 Javascript 中,供 Javascript 实例化“封装 C+类到 Javascript 中去” ,如果说可以做到,那也是没有捷径的,不存在“通过几个统一的 API 将已有的 C+类映射到 Javascript 环境中去 ”。当然也不是绝对的完全没有,像 cproxyv8 这样的类库就一定程度上简化了映射关系。但是,它只是锦上添花而已,没有从根本上改变什么。正确并且正统的做法就是像上面 2.4/2.5 介绍的,通过向运行环境映射 C+类同名Function,并不厌其烦地向此 Function 的 FunctionTempalte 注册一大堆的方法去操作(或者说是代理) “隐藏”在此 FunctionTemplate 内部的原 C+类的实例(可能直接是个指针,或者是个由 External 类包装的指针) 。 三、Google v8 的开源应用3.1 Node.js/Node.js 是一套用来编写高性能网络服务器的 JavaScript 工具包。 Node 为创建 http 服务器作了优化,我们在网上看到的大部分示例和库都是集中在

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论