Nodejs Addons

Nodejs的Addons就是动态链接库(C/C++),主要涉及的有

  • V8 Javascript, a C++ library
    • 主要用于实现Javascript的接口:creating objects, calling functions…
  • libuv,C实现的event loop library
    • 当需要执行阻塞/异步操作时,需要使用libuv,例如:等待文件就绪、等待定时器超时、等待signal…
  • internal Node libraries
    • node::Objectwrap
  • others, see deps/

       

一个简单的实例

实现功能如下的模块

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

   

C++代码如下

#include <node.h>

#include <v8.h>

   

using namespace v8;

   

Handle<Value> Method(const Arguments& args) {

HandleScope scope;

return scope.Close(String::New("world"));

}

   

void init(Handle<Object> exports) {

exports->Set(String::NewSymbol("hello"),

FunctionTemplate::New(Method)->GetFunction());

}

   

NODE_MODULE(hello, init)

   

所有的Node Addons必须实现一个初始化函数,由 NODE_MODULE指定:

NODE_MODULE(module_name, Initialize),module_name必须和最终库文件的文件名前缀匹配(module_name.node

   

C++文件由node-gyp工具进行编译,配置文件

{

"targets": [

{

"target_name": "hello",

"sources": [ "hello.cc" ]

}

]

}

运行命令

node-gyp configure

node-gyp build

   

测试代码

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

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

   

   

函数参数

   

测试代码

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

   

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

   

需要在C++代码中处理数字参数

#define BUILDING_NODE_EXTENSION

#include <node.h>

   

using namespace v8;

   

Handle<Value> Add(const Arguments& args) {

HandleScope scope;

   

if (args.Length() < 2) {

ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));

return scope.Close(Undefined());

}

   

if (!args[0]->IsNumber() || !args[1]->IsNumber()) {

ThrowException(Exception::TypeError(String::New("Wrong arguments")));

return scope.Close(Undefined());

}

   

Local<Number> num = Number::New(args[0]->NumberValue() +

args[1]->NumberValue());

return scope.Close(num);

}

   

void Init(Handle<Object> exports) {

exports->Set(String::NewSymbol("add"),

FunctionTemplate::New(Add)->GetFunction());

}

   

NODE_MODULE(addon, Init)

   

回调函数

   

回到函数也是通过参数进行传递

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

   

addon(function(msg){

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

});

   

C++代码

#define BUILDING_NODE_EXTENSION

#include <node.h>

   

using namespace v8;

   

Handle<Value> RunCallback(const Arguments& args) {

HandleScope scope;

   

Local<Function> cb = Local<Function>::Cast(args[0]);

const unsigned argc = 1;

Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };

cb->Call(Context::GetCurrent()->Global(), argc, argv);

   

return scope.Close(Undefined());

}

   

void Init(Handle<Object> exports, Handle<Object> module) {

module->Set(String::NewSymbol("exports"),

FunctionTemplate::New(RunCallback)->GetFunction());

}

   

NODE_MODULE(addon, Init)

   

   

对象工厂/Object Factory

   

函数返回一个对象

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

   

var obj1 = addon('hello');

var obj2 = addon('world');

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

   

C++代码

#define BUILDING_NODE_EXTENSION

#include <node.h>

   

using namespace v8;

   

Handle<Value> CreateObject(const Arguments& args) {

HandleScope scope;

   

Local<Object> obj = Object::New();

obj->Set(String::NewSymbol("msg"), args[0]->ToString());

   

return scope.Close(obj);

}

   

void Init(Handle<Object> exports, Handle<Object> module) {

module->Set(String::NewSymbol("exports"),

FunctionTemplate::New(CreateObject)->GetFunction());

}

   

NODE_MODULE(addon, Init)

   

与上述例子不同的是,Init函数接收第二个参数module,通过module将函数导出

   

类似,可以使函数返回一个函数

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

   

var fn = addon();

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

   

C++代码

#define BUILDING_NODE_EXTENSION

#include <node.h>

   

using namespace v8;

   

Handle<Value> MyFunction(const Arguments& args) {

HandleScope scope;

return scope.Close(String::New("hello world"));

}

   

Handle<Value> CreateFunction(const Arguments& args) {

HandleScope scope;

   

Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);

Local<Function> fn = tpl->GetFunction();

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

   

return scope.Close(fn); //区别在此

}

   

void Init(Handle<Object> exports, Handle<Object> module) {

module->Set(String::NewSymbol("exports"),

FunctionTemplate::New(CreateFunction)->GetFunction());

}

   

NODE_MODULE(addon, Init)

   

包装C++对象/Wrapping C++ objects

通过此方法,可以在Javascript中实例化C++类

   

#include <node.h>

   

using namespace v8;

   

class MyObject : public node::ObjectWrap {

public:

static void Init(v8::Handle<v8::Object> exports);

   

private:

explicit MyObject(double value = 0);

~MyObject();

   

static v8::Handle<v8::Value> New(const v8::Arguments& args);

static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);

static v8::Persistent<v8::Function> constructor;

double value_;

};

   

Persistent<Function> MyObject::constructor;

   

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

}

   

MyObject::~MyObject() {

}

   

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

// Prepare constructor template

Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

tpl->SetClassName(String::NewSymbol("MyObject"));

tpl->InstanceTemplate()->SetInternalFieldCount(1);

// Prototype

tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),

FunctionTemplate::New(PlusOne)->GetFunction());

constructor = Persistent<Function>::New(tpl->GetFunction());

exports->Set(String::NewSymbol("MyObject"), constructor);

}

   

Handle<Value> MyObject::New(const Arguments& args) {

HandleScope scope;

   

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());

return args.This();

} else {

// Invoked as plain function `MyObject(...)`, turn into construct call.

const int argc = 1;

Local<Value> argv[argc] = { args[0] };

return scope.Close(constructor->NewInstance(argc, argv));

}

}

   

Handle<Value> MyObject::PlusOne(const Arguments& args) {

HandleScope scope;

   

MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());

obj->value_ += 1;

   

return scope.Close(Number::New(obj->value_));

}

   

   

void InitAll(Handle<Object> exports) {

MyObject::Init(exports);

}

   

NODE_MODULE(addon, InitAll)

   

重点在于FunctionTemplate、ObjectWrap

   

测试代码

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

   

   

可以看出,Node Addons的基本任务在于C++和Javascript中参数的传递/转换,主要涉及V8、Node library。至于Addon的功能实现,都将和libuv紧密相关(所有的函数都应做到nonblocking)。

 

参考http://nodejs.org/api/addons.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值