|
| 1 | +## N-API简介 |
| 2 | + |
| 3 | +Node.js 8.0 在2017年6月份发布,升级的特性中,包含了N-API。编写过或者使用过 node扩展的同学,不少都遇到过升级node版本,node扩展编译失败的情况,因为node扩展严重依赖于V8暴露的API,而node不同版本依赖的V8版本可能不同,一旦升级node版本,原先运行正常的node扩展就编译失败了。 |
| 4 | + |
| 5 | +这种情况对node生态圈无疑是不利的,N-API的引入正是试图改善这种情况的一种尝试。它跟底层JS引擎无关,只要暴露的API足够稳定,那么node扩展的编写者就不用过分担忧node的升级问题。 |
| 6 | + |
| 7 | +## 如何使用N-API |
| 8 | + |
| 9 | +先强调一点,N-API并不是对原有node扩展实现方式的替代,它只是提供了一系列底层无关的API,来帮助开发者编写跨版本的node扩展。至于如何编写、编译扩展,跟原来的差不多。 |
| 10 | + |
| 11 | +本文会从一个超级简单的例子,简单介绍N-API的使用。 |
| 12 | + |
| 13 | +## 环境准备 |
| 14 | + |
| 15 | +首先,N-API是8.0版本引入的,首先确保本地安装了8.0版本。笔者用的是`nvm`,读者可自行选择安装方式。 |
| 16 | + |
| 17 | +```bash |
| 18 | +nvm i 8.0 |
| 19 | +nvm use 8.0 |
| 20 | +``` |
| 21 | + |
| 22 | +然后,安装`node-gyp`,编译扩展会用到。 |
| 23 | + |
| 24 | +```bash |
| 25 | +npm install -g node-gyp |
| 26 | +``` |
| 27 | + |
| 28 | +创建项目目录,并初始化`package.json`。 |
| 29 | + |
| 30 | +```bash |
| 31 | +mkdir hello & cd hello # 目录名随便起 |
| 32 | +npm init -f |
| 33 | +``` |
| 34 | + |
| 35 | + |
| 36 | +## 编写扩展 |
| 37 | + |
| 38 | +创建`hello.cc`作为扩展的源文件。 |
| 39 | + |
| 40 | +```bash |
| 41 | +mkdir src |
| 42 | +touch src/hello.cc |
| 43 | +``` |
| 44 | + |
| 45 | +编辑`hello.cc`,输入如下内容。 |
| 46 | + |
| 47 | +```c |
| 48 | +#include <node_api.h> |
| 49 | + |
| 50 | +// 实际暴露的方法,这里只是简单返回一个字符串 |
| 51 | +napi_value HelloMethod (napi_env env, napi_callback_info info) { |
| 52 | + napi_value world; |
| 53 | + napi_create_string_utf8(env, "world", 5, &world); |
| 54 | + return world; |
| 55 | +} |
| 56 | + |
| 57 | +// 扩展的初始化方法,其中 |
| 58 | +// env:环境变量 |
| 59 | +// exports、module:node模块中对外暴露的对象 |
| 60 | +void Init (napi_env env, napi_value exports, napi_value module, void* priv) { |
| 61 | + // napi_property_descriptor 为结构体,作用是描述扩展暴露的 属性/方法 的描述 |
| 62 | + napi_property_descriptor desc = { "hello", 0, HelloMethod, 0, 0, 0, napi_default, 0 }; |
| 63 | + napi_define_properties(env, exports, 1, &desc); // 定义暴露的方法 |
| 64 | +} |
| 65 | + |
| 66 | +NAPI_MODULE(hello, Init); // 注册扩展,扩展名叫做hello,Init为扩展的初始化方法 |
| 67 | +``` |
| 68 | +
|
| 69 | +## 编译扩展 |
| 70 | +
|
| 71 | +首先,创建编译描述文件`binding.gyp`。 |
| 72 | +
|
| 73 | +```json |
| 74 | +{ |
| 75 | + "targets": [ |
| 76 | + { |
| 77 | + "target_name": "hello", |
| 78 | + "sources": [ "./src/hello.cc" ] |
| 79 | + } |
| 80 | + ] |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +然后,运行如下命令进行编译。 |
| 85 | + |
| 86 | +```bash |
| 87 | +node-gyp rebuild |
| 88 | +``` |
| 89 | + |
| 90 | +## 调用扩展 |
| 91 | + |
| 92 | +未方便调用扩展,先安装`bindings`。 |
| 93 | + |
| 94 | +```bash |
| 95 | +npm install --save bindings |
| 96 | +``` |
| 97 | + |
| 98 | +然后,创建`app.js`,调用刚编译的扩展。 |
| 99 | + |
| 100 | +```javascript |
| 101 | +var addon = require('bindings')('hello'); |
| 102 | + |
| 103 | +console.log( addon.hello() ); // world |
| 104 | +``` |
| 105 | + |
| 106 | +运行代码,由于N-API当前尚处于Experimental阶段,记得加上`--napi-modules`标记。 |
| 107 | + |
| 108 | +```bash |
| 109 | +node --napi-modules app.js |
| 110 | +``` |
| 111 | + |
| 112 | +输出如下 |
| 113 | + |
| 114 | +```bash |
| 115 | +{"path":"/data/github/abi-stable-node-addon-examples/1_hello_world/napi/build/Release/hello.node"} |
| 116 | +world |
| 117 | +(node:6500) Warning: N-API is an experimental feature and could change at any time. |
| 118 | +``` |
| 119 | + |
| 120 | +## 相关链接 |
| 121 | + |
| 122 | +https://nodejs.org/api/n-api.html |
0 commit comments