知识共享许可协议
本作品采用知识共享署名-非商业性使用 3.0 未本地化版本许可协议进行许可。

Node.js v0.10.18 手册 & 文档


Addons插件#

Addons are dynamically linked shared objects. They can provide glue to C and C++ libraries. The API (at the moment) is rather complex, involving knowledge of several libraries:

Addons插件就是动态连接库。它类似胶水,将c、c++和Node粘贴起来。它的API(目前来说)相当复杂,涉及到了几个类库的知识。

  • V8 JavaScript, a C++ library. Used for interfacing with JavaScript: creating objects, calling functions, etc. Documented mostly in the v8.h header file (deps/v8/include/v8.h in the Node source tree), which is also available online.

  • V8 JavaScript引擎,一个 C++ 类库. 用于和JavaScript进行交互的接口。 创建对象, 调用函数等. 文档大部分在这里: v8.h 头文件 (deps/v8/include/v8.h在Node源代码目录里), 也有可用的线上文档 线上. (译者:想要学习c++的addons插件编写,必须先了解v8的接口)

  • libuv, C event loop library. Anytime one needs to wait for a file descriptor to become readable, wait for a timer, or wait for a signal to be received one will need to interface with libuv. That is, if you perform any I/O, libuv will need to be used.

  • libuv, C语言编写的事件循环类库。任何时候需要等待一个文件描述符变为可读状态,等待一个定时器,或者等待一个接受信号都需要使用libuv类库的接口。也就是说,如果你执行任何I/O操作,libuv类库将会被用到。

  • Internal Node libraries. Most importantly is the node::ObjectWrap class which you will likely want to derive from.

  • 内部 Node 类库.最重要的接口就是 node::ObjectWrap 类,这个类你应该是最可能想要派生的。

  • Others. Look in deps/ for what else is available.

  • 其他.请参阅 deps/ 获得更多可用类库。

Node statically compiles all its dependencies into the executable. When compiling your module, you don't need to worry about linking to any of these libraries.

Node 静态编译了所有依赖到它的可执行文件中去了。当编译你的模块时,你不必担心无法连接上述那些类库。 (译者:换而言之,你在编译自己的addons插件时,只管在头部 #include <uv.h>,不必在binding.gyp中声明)

All of the following examples are available for download and may be used as a starting-point for your own Addon.

下面所有的例子都可以下载到: 下载 这或许能成为你学习和创作自己addon插件的起点。

Hello world(世界你好)#

To get started let's make a small Addon which is the C++ equivalent of the following JavaScript code:

作为开始,让我们用编写一个小的addon插件,这个addon插件的c++代码相当于下面的JavaScript代码。

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

First we create a file hello.cc:

首先我们创建一个 hello.cc文件:

NODE_MODULE(hello, init)//译者:将addon插件名hello和上述init函数关联输出

Note that all Node addons must export an initialization function:

注意所有Node的addons插件都必须输出一个初始化函数:

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

There is no semi-colon after NODE_MODULE as it's not a function (see node.h).

NODE_MODULE之后没有分号,因为它不是一个函数(请参阅node.h

The module_name needs to match the filename of the final binary (minus the .node suffix).

这个module_name(模块名)需要和最后编译生成的2进制文件名(减去.node后缀名)相同。

The source code needs to be built into hello.node, the binary Addon. To do this we create a file called binding.gyp which describes the configuration to build your module in a JSON-like format. This file gets compiled by node-gyp.

源代码需要生成在hello.node,这个2进制addon插件中。 需要做到这些,我们要创建一个名为binding.gyp的文件,它描述了创建这个模块的配置,并且它的格式是类似JSON的。 文件将被命令:node-gyp 编译。

{
  "targets": [
    {
      "target_name": "hello", //译者:addon插件名,注意这里的名字必需和上面NODE_MODULE中的一致
      "sources": [ "hello.cc" ]  //译者:这是需要编译的源文件
    }
  ]
}

The next step is to generate the appropriate project build files for the current platform. Use node-gyp configure for that.

下一步是根据当前的操作系统平台,利用node-gyp configure命令,生成合适的项目文件。

Now you will have either a Makefile (on Unix platforms) or a vcxproj file (on Windows) in the build/ directory. Next invoke the node-gyp build command.

现在你会有一个Makefile (在Unix平台) 或者一个 vcxproj file (在Windows上),它们都在build/ 文件夹中. 然后执行命令 node-gyp build进行编译。 (译者:当然你可以执行 node-gyp rebuild一步搞定)

Now you have your compiled .node bindings file! The compiled bindings end up in build/Release/.

现在你已经有了编译好的 .node 文件了,这个编译好的绑定文件会在目录 build/Release/

You can now use the binary addon in a Node project hello.js by pointing require to the recently built hello.node module:

现在你可以使用这个2进制addon插件在Node项目hello.js 中了,通过指明require这个刚刚创建的hello.node模块使用它。

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

Please see patterns below for further information or

https://github.com/arturadib/node-qt for an example in production.

请阅读下面的内容获得更多详情或者访问https://github.com/arturadib/node-qt获取一个生产环境的例子。

Addon patterns(插件方式)#

Below are some addon patterns to help you get started. Consult the online v8 reference for help with the various v8 calls, and v8's Embedder's Guide for an explanation of several concepts used such as handles, scopes, function templates, etc.

下面是一些帮助你开始编写addon插件的方式。参考这个在线的v8 手册用来帮助你调用各种v8接口, 然后是v8的 嵌入式开发向导 ,解释几个概念,如 handles, scopes,function templates等。

In order to use these examples you need to compile them using node-gyp. Create the following binding.gyp file:

为了能跑起来这些例子,你必须用 node-gyp 来编译他们。 创建一个binding.gyp 文件:

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

In cases where there is more than one .cc file, simply add the file name to the sources array, e.g.:

事实上可以有多个 .cc 文件, 就简单的在 sources 数组里加上即可,例子:

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

Now that you have your binding.gyp ready, you can configure and build the addon:

现在你有了你的binding.gyp文件了,你可要开始执行configure 和 build 命令构建你的addon插件了

$ node-gyp configure build

Function arguments(函数参数)#

The following pattern illustrates how to read arguments from JavaScript function calls and return a result. This is the main and only needed source addon.cc:

下面的部分说明了如何从JavaScript的函数调用获得参数然后返回一个值。这是主要的内容并且仅需要源代码addon.cc

NODE_MODULE(addon, Init)

You can test it with the following JavaScript snippet:

你可以使用下面的JavaScript代码片段来测试它

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

Callbacks(回调)#

You can pass JavaScript functions to a C++ function and execute them from there. Here's addon.cc:

你可以传递JavaScript functions 到一个C++ function 并且执行他们,这里是 addon.cc文件:

NODE_MODULE(addon, Init)

Note that this example uses a two-argument form of Init() that receives the full module object as the second argument. This allows the addon to completely overwrite exports with a single function instead of adding the function as a property of exports.

注意这个例子对Init()使用了两个参数,将完整的 module 对象作为第二个参数传入。这允许addon插件完全的重写 exports,这样就可以用一个函数代替多个函数作为exports的属性了。

To test it run the following JavaScript snippet:

你可以使用下面的JavaScript代码片段来测试它

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

Object factory(对象工厂)#

You can create and return new objects from within a C++ function with this addon.cc pattern, which returns an object with property msg that echoes the string passed to createObject():

在这个addon.cc文件里用一个c++函数,你可以创建并且返回一个新的对象,这个新的对象拥有一个msg的属性,它的值是通过createObject()方法传入的

NODE_MODULE(addon, Init)

To test it in JavaScript:

在js中测试如下:

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

Function factory(函数工厂)#

This pattern illustrates how to create and return a JavaScript function that wraps a C++ function:

这次将展示如何创建并返回一个JavaScript function函数,这个函数其实是通过c++包装的。

NODE_MODULE(addon, Init)

To test:

测试它:

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

Wrapping C++ objects(包装c++对象)#

Here we will create a wrapper for a C++ object/class MyObject that can be instantiated in JavaScript through the new operator. First prepare the main module addon.cc:

这里将创建一个被c++包裹的对象或类MyObject,它是可以在JavaScript中通过new操作符实例化的。 首先我们要准备主要的模块文件addon.cc:

NODE_MODULE(addon, InitAll)

Then in myobject.h make your wrapper inherit from node::ObjectWrap:

然后在myobject.h文件中创建你的包装类,它继承自 node::ObjectWrap:

#endif

And in myobject.cc implement the various methods that you want to expose. Here we expose the method plusOne by adding it to the constructor's prototype:

在文件 myobject.cc 可以实施各种你想要暴露给js的方法。 这里我们暴露方法名为 plusOne给就是,它表示将构造函数的属性加1.

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

Test it with:

测试它:

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

Factory of wrapped objects(工厂包装对象)#

This is useful when you want to be able to create native objects without explicitly instantiating them with the new operator in JavaScript, e.g.

这是非常有用的,当你想创建原生的JavaScript对象时,又不想明确的使用JavaScript的new操作符。

var obj = addon.createObject();
// 用上面的方式代替下面的:
// var obj = new addon.Object();

Let's register our createObject method in addon.cc:

让我们注册在 addon.cc 文件中注册createObject方法:

NODE_MODULE(addon, InitAll)

In myobject.h we now introduce the static method NewInstance that takes care of instantiating the object (i.e. it does the job of new in JavaScript):

myobject.h文件中,我们现在介绍静态方法NewInstance,它能够实例化对象(举个例子,它的工作就像是 在JavaScript中的new` 操作符。)

#endif

The implementation is similar to the above in myobject.cc:

这里的处理方式和上面的 myobject.cc很像:

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

Test it with:

测试它:

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

Passing wrapped objects around(传递包装的对象)#

In addition to wrapping and returning C++ objects, you can pass them around by unwrapping them with Node's node::ObjectWrap::Unwrap helper function. In the following addon.cc we introduce a function add() that can take on two MyObject objects:

除了包装和返回c++对象以外,你可以传递他们并且通过Node的node::ObjectWrap::Unwrap帮助函数解包装他们。 在下面的addon.cc 文件中,我们介绍了一个函数add(),它能够获取2个MyObject对象。

NODE_MODULE(addon, InitAll)

To make things interesting we introduce a public method in myobject.h so we can probe private values after unwrapping the object:

为了使事情变得有趣,我们在 myobject.h 采用一个公共的方法,所以我们能够在unwrapping解包装对象之后使用私有成员的值。

#endif

The implementation of myobject.cc is similar as before:

myobject.cc文件的处理方式和前面类似

  return scope.Close(instance);
}

Test it with:

测试它:

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

console.log(result); // 30


console.log(result); // 30