您当前的位置: 首页 > 

顺其自然~

暂无认证

  • 2浏览

    0关注

    1317博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

V8编程详解

顺其自然~ 发布时间:2021-02-06 16:32:28 ,浏览量:2

这里选用了官方文档的一个非常简洁的HelloWorld.cc,代码如下:

#include 
 
using namespace v8;
int main(int argc, char* argv[]) {
 
  // Create a stack-allocated handle scope.
  HandleScope handle_scope;
 
  // Create a new context.
  Persistent context = Context::New();
 
  // Enter the created context for compiling and
  // running the hello world script.
  Context::Scope context_scope(context);
 
  // Create a string containing the JavaScript source code.
  Handle source = String::New("'Hello' + ', World!'");
 
  // Compile the source code.
  Handle script = Script::Compile(source);
 
  // Run the script to get the result.
  Handle result = script->Run();
 
  // Dispose the persistent context.
  context.Dispose();
 
  // Convert the result to an ASCII string and print it.
  String::AsciiValue ascii(result);
  printf("%s\n", *ascii);
  return 0;
}

我的目录结构如下:

编译运行:

g++ -I../include helloworld.cc  -o helloworld -lpthread -lv8
./helloworld

就可以在屏幕上看到输出结果了。

看到demo上有一些Context,Scope,Value等等,先不要慌张,其实就是V8的一些基本 数据类型,这些在后面会逐个一一讲到。                                                                                    

Handle source = String::New("'Hello' + ', World!'");

看到这句话,其实就是在加载一个js文件了。只不过这个js文件内容为:

'Hello' + ', World!'

那么这里,source就已经是加载过的js文件字符串内容了,接下来V8需要对js进行编译解释。

Handle script = Script::Compile(source);
Handle result = script->Run();

最后就是JS的执行了。这里虽然只有简单的几个语句,但是V8对于JS的编译和运行做了很多很复杂的操作。下面将围绕这个Demo对V8的基本类型和相关概念进行讲解。

Handle

       在V8中,内存分配都是在V8的Heap中进行分配的,JavaScript的值和对象也都存放在V8的Heap中。这个Heap由V8独立的去维护,失去引用的对象将会被V8的GC掉并可以重新分配给其他对象。而Handle即是对Heap中对象的引用。V8为了对内存分配进行管理,GC需要对V8中的所有对象进行跟踪,而对象都是用Handle方式引用的,所以GC需要对Handle进行管理,这样GC就能知道Heap中一个对象的引用情况,当一个对象的Handle引用为发生改变的时候,GC即可对该对象进行回收(gc)或者移动。因此,V8编程中必须使用Handle去引用一个对象,而不是直接通过C++的方式去获取对象的引用,直接通过C++的方式去直接去引用一个对象,会使得该对象无法被V8管理。

       Handle分为Local和Persistent两种。从字面上就能知道,Local是局部的,它同时被HandleScope进行管理。persistent,类似与全局的,不受HandleScope的管理,其作用域可以延伸到不同的函数,而Local是局部的,作用域比较小。Persistent Handle对象需要Persistent::New, Persistent::Dispose配对使用,类似于C++中new和delete。Persistent::MakeWeak可以用来弱化一个Persistent Handle,如果一个对象的唯一引用Handle是一个Persistent,则可以使用MakeWeak方法来如果该引用,该方法可以触发GC对被引用对象的回收。

HandleScope

一个函数中,可以有很多Handle,而HandleScope则相当于用来装Handle(Local)的容器,当HandleScope生命周期结束的时候,Handle也将会被释放,会引起Heap中对象引用的更新。HandleScope是分配在栈上,不能通过New的方式进行创建。对于同一个作用域内可以有多个HandleScope,新的HandleScope将会覆盖上一个HandleScope,并对Local Handle进行管理。下面通过代码来讲解HandleScope的生命周期:

#include 
 
using namespace v8;
int main(int argc, char* argv[]) {
 
  // Create a stack-allocated handle scope.
  HandleScope handle_scope;
  // >>>>>>>>>>>>>>>>>>>>>>>>从这里开始,是HandleScope的生命周期的开始
  // 从此之后的所有Local Handle都这个handle_scope对象进行管理
 
 
  // Create a new context.
  Persistent context = Context::New();   //Persistent Handle
 
  // Enter the created context for compiling and
  // running the hello world script.
  Context::Scope context_scope(context);
 
  // Create a string containing the JavaScript source code.
  Handle source = String::New("'Hello' + ', World!'"); //Local Handle
 
  // Compile the source code.
  Handle script = Script::Compile(source); //Local Handle
 
  // Run the script to get the result.
  Handle result = script->Run(); //Local Handle
 
  // Dispose the persistent context.
  context.Dispose();
 
  // Convert the result to an ASCII string and print it.
  String::AsciiValue ascii(result);
  printf("%s\n", *ascii);
  return 0;
  // start();
 
	return Undefined();
}
 
void SetupCloudAppInterface(Handle global) {
	Handle cloudapp_template = FunctionTemplate::New(CloudAppConstructCallback);
	cloudapp_template->SetClassName(String::New("CloudApp"));
 
	Handle cloudapp_proto = cloudapp_template->PrototypeTemplate();
	//这一步,完全可以使用cloudapp_inst->Set(....)
	//使用prototype更符合JS编程
	cloudapp_proto->Set(String::New("start"), FunctionTemplate::New(Start));
	cloudapp_proto->Set(String::New("state"), FunctionTemplate::New(GetState));
	cloudapp_proto->Set(String::New("appid"), FunctionTemplate::New(GetAppId));
	
	//******很重要!!!
	Handle cloudapp_inst = cloudapp_template->InstanceTemplate();
	cloudapp_inst->SetInternalFieldCount(1);
	
	//向JS世界注册一个函数,其本质就是向JS世界的global注册一个类。
	//所以,也是通过向global注入CloudApp类。
	global->Set(String::New("CloudApp"), cloudapp_template);
}
 
void InitialnilizeInterface(Handle global) {
	SetupCloudAppInterface(global);
}
 
void LoadJsAndRun() {
	Handle source = ReadJS("script.js");
	Handle script = Script::Compile(source);
	Handle result = script->Run();
 
	printValue(result);
}
 
void Regist2JsContext(Handle& object, Persistent& context) {
	context = Context::New(NULL, object);
}
 
int main(int argc, char** argv) {
	HandleScope handle_scope;
	Handle global = ObjectTemplate::New();
	Persistent context;
	
	InitialnilizeInterface(global);
	Regist2JsContext(global, context);
	Context::Scope context_scope(context);
	LoadJsAndRun();
 
	context.Dispose();
	
	return 0;
}

JS代码如下:

//script.js
var cloudapp = new CloudApp(24);
cloudapp.start();
var result;

上面的代码基本可以从函数名称和注释中明白是什么意思。最后再讲一点SetInternalFieldCount:

Handle cloudapp_inst = cloudapp_template->InstanceTemplate();
cloudapp_inst->SetInternalFieldCount(1);

在其他的操作都就绪之后还必须SetInsternalFieldCount(),这一点是为了告诉V8,我们有几个InternalField,这里是只有1个。否则,在JS和C++指针交互过程中,V8在查找InternalField的时候会越界的。

Google V8编程详工具函数

头文件:utils.h

#ifndef UTILS_H_
#define UTILS_H_
#include "v8.h"
#include 
using namespace v8;
using namespace std;
 
v8::Handle ReadJS(const char* name);
void printValue(Handle result);
#endif
  • ReadJS
v8::Handle ReadJS(const char* name) {
 
        FILE* file = fopen(name, "rb");
 
        if (file == NULL) {
                return v8::Handle();
        }
 
        fseek(file, 0, SEEK_END);
        int size = ftell(file);
        rewind(file);
 
        char* chars = new char[size + 1];
        chars[size] = '\0';
 
        for (int i = 0; i < size;) {
                int read = fread(&chars[i], 1, size - i, file);
                i += read;
        }
 
        fclose(file);
 
        v8::Handle result = v8::String::New(chars, size);
        delete[] chars;
        return result;
}
  • printValue
void printValue(Handle result) {
	//感谢downmooner兄的提醒,这个String::Utf8Value str(result)的确让这段代码
	//南辕北辙
	//String::Utf8Value str(result);
 
 
	// just construct the "result" script
	Handle script = Script::Compile(String::New("result"));
	result = script->Run();
	cout             
关注
打赏
1662339380
查看更多评论
0.0421s