先看类图
- v8:这是一个大杂烩的工具类,从初始化到关闭平台都离不开它。
- ArrayBuffer是v8的数据类型,可以参考上面的数据类型图。
- Isolate是v8中最重要的功能类,代表了一个v8引擎的实例。它不是线程安全的,如果在线程不安全的情况下运行需要加锁。
- Local是v8中存储对象的结构,代表了被GC管理的对象引用。与其对应的就是持久性对象,如Global和Persistent。
- Context代表了在沙箱中运行的上下文,JavaScript也运行在一个沙箱安全环境中。
- Script 代表了运行在v8中的脚本
源码分析
在源码中 src/d8/d8.cc 文件中
int main(int argc, char* argv[]) {
return v8::Shell::Main(argc, argv);
}
和src的同级目录中有一个samples文件夹,里面有一个 hello-world.cc ,把主体的 int main(int argc, char* argv[]) 函数内容copy,替换上面的内容,这个hello world会简单很多。
hello-world.cc中,不支持console.log功能,要额外加入
// 增加 console 能力 start
v8::D8Console console(isolate);
v8::Shell::Initialize(isolate, &console, false);
// 增加 console 能力 end
setTimeout 模块,也是hello-world.cc 中不支持的,这里比较有意思的是它默认是支持 Promise 的,但是setTimeout需要额外增加。
v8::Local<v8::String> source = v8::String::NewFromUtf8Literal(isolate,
"new Promise((resolve) => { resolve(1)" +
"}).then(res => { console.log(res); }); console.log('2')");
下面这个是修改以后的 int main(int argc, char* argv[]) 函数
修改好以后,重新执行 tools/dev/gm.py x64.debug,然后在out/x64.debug目录中,运行 ./d8 就可以看到你的执行结果了。
// d8.cc
int main(int argc, char* argv[]) {
// Initialize V8.
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
v8::HandleScope handle_scope(isolate);
// 增加 console 能力 start
v8::D8Console console(isolate);
v8::Shell::Initialize(isolate, &console, false);
// 增加 console 能力 end
v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
// 增加setTimeout支撑
// global_template->Set(isolate, "setTimeout",
// v8::FunctionTemplate::New(isolate, v8::Shell::SetTimeout));
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global_template);
// Create a new context.
// v8::Local<v8::Context> context = v8::Context::New(isolate);
// Enter the context for compiling and running the hello world script.
v8::Context::Scope context_scope(context);
{
// Create a string containing the JavaScript source code.
// try { setTimeout(function() { console.log('1'); }, 2000)} catch(e) {console.log('setTimeout is not defined ===')} finally { console.log('finally') }
// "var a = [1, 2, 3]; a.push();" 3
// "var a = [1, 2, 3]; a[1];" 2
// "var a = new Set(); a.add('a'); a" [object Set]
// 这个证明promise和setTimeout是完全不一样的机制
// "new Promise((resolve) => { resolve(1) }).then(res => { console.log(res); })" 1 [object Promise]
// 有执行顺序的区别
// "new Promise((resolve) => { resolve(1) }).then(res => { console.log(res); }); console.log('2')" 2 1 undefined
v8::Local<v8::String> source =
v8::String::NewFromUtf8Literal(isolate, "new Promise((resolve) => { resolve(1) }).then(res => { console.log(res); }); console.log('2')");
// Compile the source code.
v8::Local<v8::Script> script =
v8::Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
v8::String::Utf8Value utf8(isolate, result);
printf("%s\n", *utf8);
}
}
// Dispose the isolate and tear down V8.
isolate->Dispose();
v8::V8::Dispose();
v8::V8::DisposePlatform();
delete create_params.array_buffer_allocator;
return 0;
}