zl程序教程

您现在的位置是:首页 >  后端

当前栏目

c++ in nodejs (V8)

C++Nodejs in V8
2023-09-14 08:58:44 时间
$ npm i -g node-gyp
$ mkdir node-addons
$ cd node-addons
$ npm i nan
$ touch hello.cpp binding.gyp test.js

hello.cpp

#include <node.h>

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;

#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  args.GetReturnValue().Set( V8_STR("world") );
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "a", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

binding.gyp

{
    "targets": [
        {
            "target_name": "addon",
            "sources": ["main.cpp"],
            "include_dirs": [
                "<!(node -e \"require('nan')\")"
            ]
        }
    ]
}

test.js

const addon = require('./build/Release/addon');
console.log(addon.a());
λ node-gyp configure
λ node-gyp build
λ node test.js

打包成功后,可以使用vs打开"build/binding.sln"

v8::String to string

#include <ostream>
#include <node.h>
#include <nan.h>

using namespace std;

using v8::String;
using Nan::Utf8String;


  auto k = String::NewFromUtf8(isolate, "msg", NewStringType::kNormal).ToLocalChecked();
  string str{ *Utf8String{k} };
  printf("%s\n", str.c_str()); // msg

  // or
  // string str{ *String::Utf8Value{isolate, k} };

函数传参

#include <ostream>
#include <node.h>

using namespace std;

using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;

#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  printf("%d\n", args.Length()); // 2

  if (args.Length() < 2) {
    isolate->ThrowException(Exception::TypeError(V8_STR("Wrong number of arguments")));
    return;
  }
  
  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError( V8_STR("Wrong arguments") ));
    return;
  }
  
  double a1 = args[0].As<Number>()->Value();
  double a2 = args[1].As<Number>()->Value();
  double value = a1 + a2;
  printf("%f + %f = %f\n", a1, a2, value); // 1.000000 + 2.000000 = 3.0000003

  Local<Number> num = Number::New(isolate, value);
  args.GetReturnValue().Set(num);
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "a", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
let r = addon.a(1, 2);
console.log(r); // 3

回调函数

#include <ostream>
#include <node.h>

using namespace std;

using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value; 
#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<Context> ctx = isolate->GetCurrentContext();
  Local<Function> cb = Local<Function>::Cast(args[0]);
  const size_t argc = 2;
  Local<Value> argv[argc] = {
      V8_STR("hello"),
      V8_STR("world"),
  };
  cb->Call(ctx, Null(isolate), argc, argv).ToLocalChecked();
}

void Initialize(Local<Object> exports, Local<Object> module) {
  // module.exports = ...
  NODE_SET_METHOD(module, "exports", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
addon((a, b) => {
  console.log(a, b); // hello world
});

返回object

#include <ostream>
#include <node.h>

using namespace std;

using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;
#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<Context> ctx = isolate->GetCurrentContext();
  Local<Object> obj = Object::New(isolate);

  auto k = V8_STR("msg");
  auto v = args[0]->ToString(ctx).ToLocalChecked();
  obj->Set(ctx, k, v).FromJust();
  args.GetReturnValue().Set(obj);
}

void Initialize(Local<Object> exports, Local<Object> module) {
  NODE_SET_METHOD(module, "exports", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
let r = addon('xxx');
console.log(r); // { msg: 'xxx' }

返回函数

#include <ostream>
#include <node.h>
#include <nan.h>

using namespace std;

using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;
using Nan::Utf8String;
using v8::FunctionTemplate;
#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void MyFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  args.GetReturnValue().Set( V8_STR("hello world") );
}

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<Context> context = isolate->GetCurrentContext();

  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
  Local<Function> fn = tpl->GetFunction(context).ToLocalChecked();
  fn->SetName( V8_STR("theFunction") );
  args.GetReturnValue().Set(fn);
}

void Initialize(Local<Object> exports, Local<Object> module) {
  NODE_SET_METHOD(module, "exports", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
let r = addon();
console.log(r()); // hello world

返回Promise

#include <node.h>

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Promise;

#define V8_STR(str) String::NewFromUtf8(isolate, str, NewStringType::kNormal).ToLocalChecked()

void a(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  auto context = isolate->GetCurrentContext();

  Local<Promise::Resolver> resolver = Promise::Resolver::New(context).ToLocalChecked();
  Local<Promise> promise = resolver->GetPromise();
  args.GetReturnValue().Set( promise );

  resolver->Resolve( context, V8_STR("hello world.") );
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "a", a);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
addon.a().then((r) => {
  console.log(r); // hello world.
});

返回promise,你可以随时返回结果

#include <Windows.h>

  int r = MessageBoxA(0, "body", "title", 0);
  resolver->Resolve( context, Number::New(isolate, r) );

  // int r = MessageBoxA(0, "body", "title", 0);
  // args.GetReturnValue().Set( Number::New(isolate, r) );

See also: