已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Google v8学习笔记Google Javascript脚本引擎v8 学习笔记2010.11.14于遵义V0.1目录一、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.js163.2 v8cgi17四、参考资料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一定非常爽吧?varsocket=newSocket(Socket.PF_INET,Socket.SOCK_STREAM,Socket.IPPROTO_TCP);socket.setOption(Socket.SO_REUSEADDR,true);varconn=socket.connect(,80);if(conn)varhttpHeader=GET /pansunyou HTTP/1.1rnHost: rnrn;socket.send(httpHeader);varresponseText=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(); / 万一不是我们预期的函数。之后便可以方便地转换为我们熟悉的V8类型了,比如String,Int32,Function,Array等等。源码之下无秘密(辅助性的函数参考本文尾部源码包):fromCppToJavaScript.js:varConfig=testString:HelloWorld,testInt:1234,testFunc:function(hello)printf(testFunc:+hello+n);varglobalStr=hi, I am globalStr.;varglobalInt=-12345;varglobalFunction=function(a,b)returna+b;printf(hello from fromCppToJavaScript.js !n);/ brief 学习如何在c+中访问javascript脚本中的变量及函数/ param argv1 演示用的jsintfromCppToJavaScript(intargc,char*argv)if(argc!=2)printf(参数错误! x.exe fromCppToJavaScript.jsn);return0;HandleScopehandleScope;Handlecontext=Context:New();Context:ScopecontextScope(context);/javascript中无打印函数HandleglobalObj=Context:GetCurrent()-Global();globalObj-Set(String:New(printf),FunctionTemplate:New(_printfForJS)-GetFunction();stringscriptFileText=tk:getFileContents(argv1);if(scriptFileText.length()=0)printf(无法打开js文件!n);return0;HandlescriptSource=String:New(scriptFileText.c_str();/编译脚本TryCatchcatcher;Handlescript=Script:Compile(scriptSource);if(catcher.HasCaught()tk:printError(&catcher);return0;/执行脚本Handleresult=script-Run();if(catcher.HasCaught()tk:printError(&catcher);return0;/Run()之后便可以访问script中的变量及函数了/1. 访问全局String变量 globalStrHandle_globalStr=globalObj-Get(String:New(globalStr);if(_globalStr.IsEmpty()printf(脚本中无globalStr变量!n);elseprintf(globalStr=%sn,*String:Utf8Value(_globalStr);/2. 全局整型变量 globalIntHandle_globalInt=globalObj-Get(String:New(globalInt);if(_globalInt.IsEmpty()printf(脚本中无globalInt变量!n);elseprintf(globalInt=%dn,_globalInt-ToInt32()-Value();/3. 调用全局函数globalFunctionHandle_globalFunction=globalObj-Get(String:New(globalFunction);if(_globalFunction.IsEmpty()|!_globalFunction-IsFunction()printf(脚本中无globalFunction函数!n);elseLocalv1=Int32:New(123);Localv2=Int32:New(456);Handlefunc=Handle:Cast(_globalFunction);Handleargs2=v1,v2;HandletmpCallVal=func-Call(globalObj,2,args);if(tmpCallVal-IsInt32()printf(globalFunction(%d,%d)=%dn,v1-ToInt32()-Value(),v2-ToInt32()-Value(),tmpCallVal-ToInt32()-Value();elseprintf(Error: globalFunction返回的应该是int才对.n);/4. 访问全局对象ConfigHandle_Config=globalObj-Get(String:New(Config);if(_Config.IsEmpty()printf(脚本中无Config变量!n);elseif(_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);elseHandleConfigTestFun=Handle:Cast(_testFunc);Handleargs=String:New(callJavascriptFunctionFromCppn);ConfigTestFun-Call(globalObj,1,args);return0;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.jsvartest=dumpArray:function()printf(fromJavaScriptToCpp:dumpArrayn);/测试访问全局变量testArrayvar_type=typeof(testArray);varlen=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中varsocket=newSocket(Socket.PF_INET,Socket.SOCK_STREAM,Socket.IPPROTO_TCP);socket.setOption(Socket.SO_REUSEADDR,true);varconn=socket.connect(,80);if(conn)//pansunyouvarhttpHeader=GET /pansunyou HTTP/1.1rnHost: rnrn;socket.send(httpHeader);varresponseText=socket.receive(12000);printf(responseText=+responseText+nn);socket.close();,testTestObj:function()printf(fromJavaScriptToCpp:testTestObjn);varobj=newTestObj;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:/仅供测试classCTestObjpublic:CTestObj()printf(CTestObj:CTestObjn);buffer=(char*)malloc(1024*1024);CTestObj()printf(CTestObj:CTestObjn);if(buffer)free(buffer);buffer=NULL;voidprintfName()printf(CTestObj:printfName name=%sn,name.c_str();voidsetName(constchar*xname)name=xname;stringname;char*buffer;/此函数用来做为TestObj的构造函数/在 var obj = new TestObj; 的时候调用JS_METHOD(_testObjConstructor)ASSERT_CONSTRUCTOR;SAVE_PTR(0,newCTestObj();returnargs.This();/只是个包装JS_METHOD(_testObjPrintName)CTestObj*pObj=LOAD_PTR(0,CTestObj*);if(pObj!=NULL)pObj-printfName();returnargs.This();/只是个包装JS_METHOD(_testObjSetName)CTestObj*pObj=LOAD_PTR(0,CTestObj*);if(pObj!=NULL)String:AsciiValuexname(args0);pObj-setName(*xname);returnargs.This();/用来显式地释放内部数据/obj.dispose();JS_METHOD(_testObjDispose)CTestObj*pObj=LOAD_PTR(0,CTestObj*);if(pObj!=NULL)deletepObj;pObj=NULL;SAVE_PTR(0,pObj);returnargs.This();/ brief 在javascript环境中构造一个class TestObj/ confused v8的垃圾回收机制还没弄明白, 这里的TestObj必须显式释放: obj.dispose();/HandlepubishCppClass_TestObj()v8:HandleScopehandle_scope;/指定构造函数v8:Handleft=v8:FunctionTemplate:New(_testObjConstructor);ft-SetClassName(JS_STR(TestObj);/在javascript的class内放一个C+实例, *CTestObj/所以要设定InternalFieldCount为1v8:Handleit=ft-InstanceTemplate();it-SetInternalFieldCount(1);/* *CTestObj */类的成员函数v8:Handlept=ft-PrototypeTemplate();pt-Set(printName,v8:FunctionTemplate:New(_testObjPrintName);pt-Set(setName,v8:FunctionTemplate:New(_testObjSetName);/用来释放内部数据.pt-Set(dispose,v8:FunctionTemplate:New(_testObjDispose);returnhandle_scope.Close(ft);externHandlepubishJavascriptClass_Socket();/ brief 学习如何在javascript中访问c+中的变量及函数/ param argv1 演示用的jsintfromJavaScriptToCpp(intargc,char*argv)if(argc!=2)printf(参数错误! x.exe fromJavaScriptToCpp.jsn);return0;HandleScopehandleScope;Handlecontext=Context:New();Context:ScopecontextScope(context);/javascript中无打印函数HandleglobalObj=Context:GetCurrent()-Global();globalObj-Set(String:New(printf),FunctionTemplate:New(_printfForJS)-GetFunction();stringscriptFileText=tk:getFileContents(argv1);if(scriptFileText.length()=0)printf(无法打开js文件!n);return0;/为脚本构造一个执行环境/1. 创建一个字符串数组(当然也可以是其它类型)Handle_array=Array:New();char*strList=hello,the,world;for(inti=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.(怎么表述?)Handlebb=pubishJavascriptClass_Socket();globalObj-Set(String:New(Socket),bb-GetFunction();/4. 包装一个含有真正C+类实体的javascript class/confused v8的垃圾回收机制还没弄明白, 这里的TestObj必须显式释放: obj.dispose();Handlecc=pubishCppClass_TestObj();globalObj-Set(String:New(TestObj),cc-GetFunction();/还有其它一些东西,比如SetAccessor/有空再研究/globalObj-SetAccessor()/最后,环境准备好后,可以执行脚本了.HandlescriptSource=String:New(scriptFileText.c_str();/编译脚本TryCatchcatcher;Handlescript=Script:Compile(scriptSource);if(catcher.HasCaught()tk:printError(&catcher);return0;/执行脚本Handleresult=script-Run();if(catcher.HasCaught()tk:printError(&catcher);return0;/confused 这样清理有用么?v8:Handlekeys=JS_GLOBAL-GetPropertyNames();intlength=keys-Length();for(inti=0;ilength;i+)v8:Handlekey=keys-Get(JS_INT(i)-ToString();JS_GLOBAL-ForceDelete(key);return0;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); / 这个没什么意思/第二步:指定此Object背后“藏”了多少数据(其实这步是可选的)/在javascript的Object内放置一些C/C+才有的数据/可以直接保存void *,也可以通过External类来包装一下v8:Handle it = ft-InstanceTemplate();it-SetInternalFieldCount(1); /第三步:指定类的成员函数 /其实这些FunctionTempalte:New()中包含的都是全局函数,他们的参数都是一模一样的 /都是 Const Arguments&args,通过它,我们可以找出“调用它的Object” /args.This(),然后GetPointerFromInternalField()取出内部数据 /或者也可以通过args.Holder()来提取内部数据。v8:Handle pt = ft-PrototypeTemplate();pt-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是一套用来编写高性能
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 48336.101-2026星闪无线通信系统第101部分:架构和通用要求
- T/ZGZS 0505-2023再生棉纱线产品碳足迹核算方法
- T/HSIPA 025-2022中医拨筋技术操作规范
- T/CISIA 008-2024电子级过硫酸盐
- T/CARD 007-2020智力障碍者用可穿戴定位设备技术要求和测试方法
- T/CSCB 0027-2024人胰岛
- 2025~2026学年内蒙古呼伦贝尔市鄂伦春自治旗人教版六年级下册期末考试数学试卷【附答案】
- 2025~2026学年广东省揭阳市普宁市人教版六年级上册学习评价(二)数学试卷【附答案】
- 2025-2026学年河南省林州市初中政治八年级期末下册自测模拟高分特训题(附答案)
- 2025-2026学年江西省樟树市初中政治八年级期末下册高分预测黑金试卷附答案
- 四川成都兴城人居地产投资集团股份有限公司招聘笔试题库2025
- 《沙漠砂混凝土应用技术规程》
- 2025年人工智能训练师职业技能认证模拟试卷及答案(金融数据标注规范)
- 黄石住房公积金管理办法
- 孔探培训课件
- DB4405∕T 315-2025 非物质文化遗产 潮阳英歌
- CJ/T 120-2016给水涂塑复合钢管
- T/CECS 10214-2022钢面镁质复合风管
- 秸秆粉碎合同协议书
- 中级个人理财-2025中级银行从业资格考试《个人理财》预测试卷6
- 建筑安装工程设备与材料的划分
评论
0/150
提交评论