四、V8 引擎的使用,hello world

425 阅读2分钟

先看类图

v8 类图.png

v8数据类型.png

  • 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;
}