Node C++扩展教程1:实现hello world

1.引言

nodejs为我们提供了丰富的API,使我们能够轻松应对多种场景。

但是太浮华的东西总感觉不踏实,尤其在nodejs面对系统硬件资源的时候。

当我们想要访问串口,i2c,spi等硬件资源时,只能去借助前人开发的库。

nodejs的使用者中,前端工程师占据了一大半。他们根本不关心硬件资源,从而导致这方面的库比较少。

难道我们就此放弃,又回到c语言刀耕火种的年代吗?或者另投其他门派,自废武功?

与其浅尝辄止,不如深入研究,多多压榨nodejs的剩余价值。

那么,让我们练习用c++为nodejs写插件吧。nodejs无法搞定的时候,就祭出c++神器。

2.c++扩展的前世今生

原生API开发:

在早期的时候,Node.js 原生 C++ 模块开发方式是非常暴力的,直接使用其提供的原生模块开发头文件。开发者直接深入到 Node.js 的各种 API,以及 Google V8 的 API。

弊端:

Node.js 原生模块开发的时候,一个版本只能支持特定几个版本的 Node.js,一旦 Node.js 的底层 API 以及 Google V8 的 API 发生变化,而这些原生模块又依赖了变化了的 API 的话,包就作废了。除非包的维护者去支持新版的 API,不过这样依赖,老版 Node.js 下就又无法编译通过新版的包了。

NAN API开发:

它全称 Native Abstractions for Node.js,即 Node.js 原生模块抽象接口。

NAN会判断当前编译时候的 Node.js 版本,自动适配不同版本的 Node.js 来展开不同的结果。我们扔按照原方式使用NAN API,而不用关心底层API更新的内容。

这样做的好处就是,代码只需要随着 NAN 的升级做改变就好,它会帮你兼容各不同 Node.js 版本,使其在任意版本都能被编译使用。

符合 ABI 的 N-API:

自从 Node.js v8.0.0 发布之后,Node.js 推出了全新的用于开发 C++ 原生模块的接口,N-API。

N-API 相较于 NAPI 来说,它把 Node.js 的所有底层数据结构全部黑盒化,抽象成 N-API 当中的接口。

不同版本的 Node.js 使用同样的接口,这些接口是稳定地 ABI 化的,即应用二进制接口(Application Binary Interface)。这使得在不同 Node.js 下,只要 ABI 的版本号一致,编译好的 C++ 扩展就可以直接使用,而不需要重新编译。事实上,在支持 N-API 接口的 Node.js 中,的确就指定了当前 Node.js 所使用的 ABI 版本。

为了使得以后的 C++ 扩展开发、维护更方便,N-API 致力于以下的几个目标:

  • 以 C 的风格提供稳定 ABI 接口;

  • 消除 Node.js 版本的差异;

  • 消除 JavaScript 引擎的差异(如 Google V8、Microsoft ChakraCore 等)。

而这些 API 主要就是用来创建和操作 JavaScript 的值了,我们就再也不用直接使用 Google V8 提供的数据类型了。毕竟在 NAN 中,就算我们有时候看不到 Google V8 的影子,实际上在宏展开后还是无数的 Google V8 数据结构。

为了达成上述隐藏的目标,N-API 的姿势就变成了这样:

  • 提供头文件 node_api.h

  • 任何 N-API 调用都返回一个 napi_status 枚举,来表示这次调用成功与否;

  • N-API 的返回值由于被 napi_status 占坑了,所以真实返回值由传入的参数来继承,如传入一个指针让函数操作;

  • 所有 JavaScript 数据类型都被黑盒类型 napi_value 封装,不再是类似于 v8::Objectv8::Number 等类型;

  • 如果函数调用不成功,可以通过 napi_get_last_error_info 函数来获取最后一次出错的信息。

3.N-API详细介绍

关于N-API的详细介绍可以查阅如下网址:

http://nodejs.cn/api/n-api.html

4.基于N-API实现的Hello World

//引入头文件
#include <node_api.h>
#include <iostream>

using namespace std;

//定义SayHello方法
napi_value SayHello(napi_env env,napi_callback_info info){
  cout << "hello world" << endl;
  return NULL;
}

//初始化object exports,将需要导出的方法或者属性挂载到object exports上
napi_value Init(napi_env env, napi_value exports){
  napi_status status;
  napi_value method;

  status = napi_create_function(env,"exports",NAPI_AUTO_LENGTH,SayHello,NULL,&method);
  if(status!= napi_ok){
    return NULL;
  }

  status = napi_set_named_property(env,exports,"sayHello",method);
  if(status != napi_ok){
    return NULL;
  }

  return exports;
}

// 注册当前module
NAPI_MODULE(NODE_GYP_MODULE_NAME,Init)

使用方法类似nodejs中的模块导出方式:

module.exports={
    //添加属性
}

完整的实现代码可以到github拉取:

https://github.com/xqli82/Napi-Test

学习更多知识,加QQ群:1098090823
威武网 » Node C++扩展教程1:实现hello world

提供最优质的资源集合

立即查看 了解详情