多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

中國最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2

nodejs教程

Node.js C/C++ 插件

閱讀 (2391)

C/C++ 插件

插件 Addons 是動態鏈接的共享對象。他提供了 C/C++ 類庫能力。這些API比較復雜,他包以下幾個類庫:

  • V8 JavaScript, C++ 類庫。用來和 JavaScript 交互,比如創建對象,調用函數等等。在 v8.h 頭文件中 (目錄地址deps/v8/include/v8.h),線上地址online

  • libuv,C 事件循環庫。等待文件描述符變為可讀,等待定時器,等待信號時,會和 libuv 打交道。或者說,如果你需要和 I/O 打交道,就會用到 libuv。

  • 內部 Node 類庫。 其中最重要的類 node::ObjectWrap,你會經常派生自它。

  • 其他的參見 deps/

Node 已經將所有的依賴編譯成可以執行文件,所以你不必當心這些類庫的鏈接問題。

以下所有例子可以在download 下載,也許你可以從中找一個作為你的擴展插件。

Hello world

現在我們來寫一個 C++ 插件的小例子,它的效果和以下 JS 代碼一致:

module.exports.hello = function() { return 'world'; };

創建 hello.cc 文件:

// hello.cc
#include <node.h>

using namespace v8;

void Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
}

void init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(addon, init)

注意:所有的 Node 插件必須輸出一個初始化函數:

void Initialize (Handle<Object> exports);
NODE_MODULE(module_name, Initialize)

NODE_MODULE 之后的代碼沒有分號,因為它不是一個函數 (參見node.h)。

module_name 必須和二進制文件名字一致 (后綴是 .node)。

源文件會編譯成 addon.node 二進制插件。 為此我們創建了一個很像 JSON 的 binding.gyp 文件, 它包含配置信息,這個文件用node-gyp編譯。

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "hello.cc" ]
    }
  ]
}

下一步創建一個 node-gyp configure 工程,在平臺上生成這些文件。

創建后,在build/文件夾里擁有一個 Makefile (Unix 系統) 文件或者 vcxproj 文件(Windows 系統)。 接著調用 node-gyp build 命令編譯,生成 .node 文件。 這些文件在 build/Release/ 目錄里。

現在,你能在 Node 工程中使用這些 2 進制擴展插件,在 hello.js 中聲明require之前編譯的hello.node:

// hello.js
var addon = require('./build/Release/addon');

console.log(addon.hello()); // 'world'

更多的信息請參考https://github.com/arturadib/node-qt

插件模式

下面是一些 addon 插件的模式,幫助你開始編碼。v8 reference 文檔里包含 v8 的各種接口,Embedder's Guide這個文檔包含各種說明,比如 handles, scopes, function templates, 等等。

在使用這些例子前,你需要先用 node-gyp 編譯。創建binding.gyp 文件:

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}

將文件名加入到 sources 數組里就可以使用多個 .cc 文件,例如 :

"sources": ["addon.cc", "myexample.cc"]

準備好 binding.gyp 文件后, 你就能配置并編譯插件:

$ node-gyp configure build

函數參數

從以下模式中解釋了如何從 JavaScript 函數中讀取參數,并返回結果。僅需要一個addon.cc文件:

// addon.cc
#include <node.h>

using namespace v8;

void Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.Length() < 2) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }

  double value = args[0]->NumberValue() + args[1]->NumberValue();
  Local<Number> num = Number::New(isolate, value);

  args.GetReturnValue().Set(num);
}

void Init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(addon, Init)

可以用以下的 JavaScript 代碼片段測試:

// test.js
var addon = require('./build/Release/addon');

console.log( 'This should be eight:', addon.add(3,5) );

回調Callbacks

你也能傳 JavaScript 函數給 C++ 函數,并執行它。 在 addon.cc 中:

// addon.cc
#include <node.h>

using namespace v8;

void RunCallback(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<Function> cb = Local<Function>::Cast(args[0]);
  const unsigned argc = 1;
  Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
  cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
}

void Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", RunCallback);
}

NODE_MODULE(addon, Init)

注意,這個例子中使用了 Init() 里的 2 個參數,module對象是第二個參數。它允許 addon 使用一個函數完全重寫 exports

可以用以下的代碼來測試:

// test.js
var addon = require('./build/Release/addon');

addon(function(msg){
  console.log(msg); // 'hello world'
});

對象工廠

addon.cc 模式里,你能用 C++ 函數創建并返回一個新的對象,這個對象所包含的 msg 屬性是由createObject() 函數傳入:

// addon.cc
#include <node.h>

using namespace v8;

void CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<Object> obj = Object::New(isolate);
  obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString());

  args.GetReturnValue().Set(obj);
}

void Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", CreateObject);
}

NODE_MODULE(addon, Init)

使用 JavaScript 測試:

// test.js
var addon = require('./build/Release/addon');

var obj1 = addon('hello');
var obj2 = addon('world');
console.log(obj1.msg+' '+obj2.msg); // 'hello world'

工廠模式

這個模式里展示了如何創建并返回一個 JavaScript 函數,它是由 C++ 函數包裝的 :

// addon.cc
#include <node.h>

using namespace v8;

void MyFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world"));
}

void CreateFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
  Local<Function> fn = tpl->GetFunction();

  // omit this to make it anonymous
  fn->SetName(String::NewFromUtf8(isolate, "theFunction"));

  args.GetReturnValue().Set(fn);
}

void Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", CreateFunction);
}

NODE_MODULE(addon, Init)

測試:

// test.js
var addon = require('./build/Release/addon');

var fn = addon();
console.log(fn()); // 'hello world'

包裝 C++ 對象

以下會創建一個 C++對象的包裝MyObject,這樣 他就能再 JavaScript 中用 new 實例化。首先在addon.cc中準備主要模塊:

// addon.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

void InitAll(Handle<Object> exports) {
  MyObject::Init(exports);
}

NODE_MODULE(addon, InitAll)

接著在 myobject.h 創建包裝,它繼承自 node::ObjectWrap:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>
#include <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init(v8::Handle<v8::Object> exports);

 private:
  explicit MyObject(double value = 0);
  ~MyObject();

  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

myobject.cc 中實現各種暴露的方法,通過給構造函數添加 prototype 屬性來暴露 plusOne 方法:

// myobject.cc
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init(Handle<Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "MyObject"),
               tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
  obj->value_ += 1;

  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}

測試:

// test.js
var addon = require('./build/Release/addon');

var obj = new addon.MyObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

包裝對象工廠

當你想創建本地對象,又不想在 JavaScript 中嚴格的使用 new 初始化的時候,以下方法非常實用。

var obj = addon.createObject();
// instead of:
// var obj = new addon.Object();

addon.cc 中注冊 createObject 方法:

// addon.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

void CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  MyObject::NewInstance(args);
}

void InitAll(Handle<Object> exports, Handle<Object> module) {
  MyObject::Init();

  NODE_SET_METHOD(module, "exports", CreateObject);
}

NODE_MODULE(addon, InitAll)

myobject.h 中有靜態方法 NewInstance,他能實例化對象 (它就像 JavaScript 的 new):

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>
#include <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);

 private:
  explicit MyObject(double value = 0);
  ~MyObject();

  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

這個實現方法和 myobject.cc 類似:

// myobject.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init() {
  Isolate* isolate = Isolate::GetCurrent();
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);

  constructor.Reset(isolate, tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Function> cons = Local<Function>::New(isolate, constructor);
  Local<Object> instance = cons->NewInstance(argc, argv);

  args.GetReturnValue().Set(instance);
}

void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
  obj->value_ += 1;

  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}

測試:

// test.js
var createObject = require('./build/Release/addon');

var obj = createObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

var obj2 = createObject(20);
console.log( obj2.plusOne() ); // 21
console.log( obj2.plusOne() ); // 22
console.log( obj2.plusOne() ); // 23

傳遞包裝對象

除了包裝并返回 C++ 對象,你可以使用 Node 的 node::ObjectWrap::Unwrap 幫助函數來解包。在下面的 addon.cc 中,我們介紹了一個 add() 函數,它能獲取2個 MyObject對象:

// addon.cc
#include <node.h>
#include <node_object_wrap.h>
#include "myobject.h"

using namespace v8;

void CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  MyObject::NewInstance(args);
}

void Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
      args[0]->ToObject());
  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
      args[1]->ToObject());

  double sum = obj1->value() + obj2->value();
  args.GetReturnValue().Set(Number::New(isolate, sum));
}

void InitAll(Handle<Object> exports) {
  MyObject::Init();

  NODE_SET_METHOD(exports, "createObject", CreateObject);
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(addon, InitAll)

介紹 myobject.h 里的一個公開方法,它能在解包后使用私有變量:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <node.h>
#include <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static void Init();
  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
  inline double value() const { return value_; }

 private:
  explicit MyObject(double value = 0);
  ~MyObject();

  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

myobject.cc 的實現方法和之前的類似:

// myobject.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init() {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  constructor.Reset(isolate, tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Function> cons = Local<Function>::New(isolate, constructor);
  Local<Object> instance = cons->NewInstance(argc, argv);

  args.GetReturnValue().Set(instance);
}

測試:

// test.js
var addon = require('./build/Release/addon');

var obj1 = addon.createObject(10);
var obj2 = addon.createObject(20);
var result = addon.add(obj1, obj2);

console.log(result); // 30
關閉
程序員人生
主站蜘蛛池模板: 非洲黑人最猛性xxxx交 | 日本一区二区视频免费播放 | 男女啪啪成人免费网站 | 成年人小视频在线观看 | 无人精品乱码一区二区三区 | 69视频在线观看 | 亚洲精品老司机综合影院 | 免费观看性欧美毛片 | 不卡视频一区二区三区 | 天天天做天天天天爱天天想 | 无码中文av有码中文av | 国产亚洲精品久久久久久小说 | 一区二区三区四区在线免费观看 | 亚洲精品天堂在线 | 琪琪777影院在线观看 | 欧美性最猛xxxx在线观看视频 | 欧美人与牲动交xxxxbbbb | 欧美成人毛片在线视频 | 国产日产欧产精品精品推荐小说 | 免费一级特黄欧美大片久久网 | 日本成a人免费视频 | aa一级黄色片| 亚洲欧美成人中文在线网站 | 99热成人精品国产免国语的 | 男女性免费视频观看 | 欧美第一色 | 啪啪网站视频 | 无人精品乱码一区二区三区 | 韩国三级一线观看久 | 国产欧美日韩在线人成aaaa | 亚洲图片小说区 | 一级a性色生活片毛片 | 狠狠干天天爱 | 国产第一页在线观看 | 欧美日韩一区二区三区自拍 | 日韩一区二区三区中文字幕 | 最近中文字幕mv免费高清视频免费 | 欧美日韩一区二区亚洲 | 香蕉久久夜色精品国产2020 | 日韩小视频在线播放 | 亚洲黄色影视 |