编写原生的Node.js模块
通常,我们开发原生Node.js模块包括但不仅限于以下原因:
对性能有比较苛刻要求的应用。尽管Node.js得益于libuv,在异步I/O操作很有优势,但遇到数字计算时并不是一个很好的选择。
使用更加底层的API,比如操作系统层面的。
在C/C++和Node.js之间创建一个Bridge,进行通信。
什么是原生模块?
Node.js Addons是动态链接的可共享对象,由C/C++编写而成。可以在Node.js中通过require()方法进行调用,使用起来像调用Node.js普通模块一样。 —— 来自Node.js官方文档
这意味着如果处理得当的话,模块调用者使用由C/C++编写的原生模块的方式和由Node.js编写的模块一样。想要编写Node.js addons,你需要了解一些基本知识:
Libuv
V8
Node.js internals
推荐阅读这些资料。
创建Node.js的原生扩展模块
下面我以一个常见的动态规划问题-青蛙跳台阶为例子来说明如何创建一个原生的Node.js模块。青蛙跳台阶描述为:一只青蛙一次可以跳上一级台阶,也可以跳上2级台阶,求该青蛙跳上n级台阶的共有多少种跳法?
首先创建一个frog_jump.cc原生文件,.cc的意思是c with class,扩展名也可以是.cpp。Google Style Guide建议使用.cc,那么此处还是以.cc做为扩展名吧。代码如下:
#include <node.h>#include<vector>/*** Native method, calculate all ways frog jump to a target stair.*/int climbStairs(int n) { std::vector<int> dp(n);dp[1] = 1;dp[2] = 2; for (int i = 3; i <= n; i ++ ) {dp[i] = dp[i - 1] + dp[i - 2];} return dp[n]; }/*** Export native method jumpTo*/void JumpTo(const v8::FunctionCallbackInfo<v8::Value>& args) {v8::Isolate* isolate = args.GetIsolate(); // Check input typeif (!args[0] -> IsNumber()) {isolate -> ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, "Wrong arguments type!")));} int value = climbStairs(args[0] -> NumberValue());v8::Local<v8::Number> num = v8::Number::New(isolate, value);args.GetReturnValue().Set(num); }// init is entry point.void init(v8::Local<v8::Object> exports) {NODE_SET_METHOD(exports, "jumpTo", JumpTo); }NODE_MODULE(frog_jump, init)
对这段代码的解释:
#include "node.h" 是c++里面引入头文件的方式,具体源码:node.h,C++链接时会加载这个头文件。头文件里面引入了v8命名空间,我们可以通过v8::标志来访问v8的接口。访问所有v8的类型,都需要使用v8::标志
通过args对象来访问Node.js传递过来的参数,通过args也可以获取调用相关信息。
通过v8::Isolate*可以获取函数作用域,可以像JS里面一样进行变量赋值,而不用担心垃圾回收问题,垃圾回收器会自动进行。
args.GetReturnValue()可以对函数返回的结果进行设置。
任何原生Node.js模块都需要调用NODE_MODULE,NODE_MODULE是一个宏,它会进行模块注册操作。
C++ 有丰富的内置类型来保存数字或者字符串,但是JS只能识别v8::里面定义的类型。因此,将c++的变量赋值给JS时,需要转换成可以被JS识别的类型,也即是v8::定义的类型。比如v8::String、v8::Object。
编译原生的Node.js模块
一旦源代码编写完成,需要将它编译成二进制的addon.node文件,之后才能被Node.js require。为了完成编译操作,需要在项目的根目录创建binding.gyp文件,里面定义了Build的配置。binding.gyp的内容是一个JSON。
{"targets": [{"target_name": "frog_jump","sources": [ "frog_jump.cc" ]}] }
编译环境配置:
windows: 以管理员的身份运行npm install --global --production windows-build-tools,这个会安装所有编译依赖的工具。
linux: 安装python v2.7、make和GCC
osx: 安装xcode
虽然npm内置了一个node-gyp版本,但是这个版本没有开放给开发者进行调用。npm install的时候会调用它来进行编译和安装工作。因此,开发者想要调用node-gyp必须自己安装一个全局的node-gyp版本。
$ npm install node-gyp -g $ node-gyp configure $ node-gyp build
运行node-gyp configure命令会生成一个跨平台的build文件,unix环境会生成Makefile,windows环境会在build目录里面生成vcxproj。
运行node-gyp build命令会生成可被Node.js调动的addon.node二进制文件。
Node.js中调用原生模块
const frogJump = require('./build/Release/frog_jump');frogJump.jumpTo(20); //青蛙跳到第20个台阶的所有方法
编写原生的Node.js模块相关推荐
- node mocha_如何使用Mocha和Assert测试Node.js模块
node mocha The author selected the Open Internet/Free Speech Fund to receive a donation as part of t ...
- Node.js「一」—— Node.js 简介 / Node.js 模块 / 包 与 NPM
本文为 Node.js 系列笔记第一篇.文章参考:nodejs 教程 -- 大地:<深入浅出 Node.js>:阮一峰 nodejs 博客 文章目录 一.Node 简介 1. 简单介绍 2 ...
- 不再为 Node.js 模块自动引入 Polyfills
在早期,webpack 的目的是为了让大多数的 Node.js 模块运行在浏览器中,但如今模块的格局已经发生了变化,现在许多模块主要是为前端而编写.webpack <= 4 的版本中提供了许多 ...
- node 大写_大写Node.js模块
node 大写 Today, let's see a third party module that helps us in working with upper-case letters witho ...
- Node.js 模块之Nimble流程控制
NodeJS异步的特性有时候会导致程序非常的难看,回调一层套着一层,这个时候就要用流程控制模块来控制究竟是同步还是异步了. Nimble是一个轻量.可移植的函数式流程控制模块.经过最小化和压缩后只有8 ...
- 如何使用async / await和Firebase数据库编写漂亮的Node.js API
by Paul Breslin 保罗·布雷斯林(Paul Breslin) 如何使用async / await和Firebase数据库编写漂亮的Node.js API (How to write ...
- (8)Node.js 模块介绍
一.Node.js模块介绍 模块(包)是 Node.js 中具有特定功能的对象. 二.web浏览器端和Node端的对比图 我们通过如上图可以看到,再web浏览器端的基本语法,再Node端也能使用,但是 ...
- node.js 模块_如何创建Node JS可重用模块
node.js 模块 In my previous post, we have discussed about "How to export and import a Node JS Mod ...
- Node.js---02、node.js 模块加载机制
2019独角兽企业重金招聘Python工程师标准>>> node.js模块分为自定义模块.扩展模块和核心模块.所有模块的加载都是通过关键字require()实现. 1.自定义模块的加 ...
最新文章
- C++复制控制:拷贝构造函数
- 厦门大学计算机专业录取分数线2019,厦门大学2019年本科生录取分数线
- 独家 | 一文读懂Apache Flink技术
- php7.1 改动,PHP7错误处理机制修改
- C#可用的日出日落时间类
- python 监视图_python获取zabbix监控图
- 前端学习(1808):前端调试之微博头部开发
- spring学习(39):注入map类型
- [转载]了解Linux的进程与线程
- 深入理解JVM(4)——如何优化Java GC
- 工控HMI界面设计基本原则
- RocKey4加密狗复制软件及教程
- 使用python+selenium谷歌浏览器驱动查排名
- 78个学术网站!史上最全常用文献数据库汇总!
- 虚幻4_添加武器插槽到骨骼
- 关于VMware VAAI说明
- IT咨询,从问题到主义
- 1953年克里克和沃森发现DNA双螺旋结构
- NanShan HTML 5与Flex是两种截然不同的技术解决方案
- 用Python写一个天天酷跑