面向未来-使用neon来拓展我们的nodejs

569 阅读3分钟

今天来介绍一个通过rust来为nodejs编写原生nodejs模块的binding

Electrify your Node with the power of Rust!

neon的优势在于:

  • No build scripts. No finicky system dependencies. Just Node and Rust.
  • If a Neon module compiles, it is guaranteed by the Rust compiler to be memory-safe.
  • Safely run multiple threads—without data races. 上面是官网对于neon的三点优势介绍,概括的来说就是体积小,易使用,内存安全的。

简单入门

第一步:首先确保电脑安装了rust的环境,如cargorustcrustup等命令,其次需要有nodejs环境以及npm。接着在命令后输入:

npm init neon hello

这一步会在当前目录创建hello项目文件夹,然后利用npm初始化一个node项目。安装完之后,会得到一个rust项目目录。在目录的src下面有一个lib.rs的文件,在这里可以开始开发我们想开发的node模块,上面的命令中会帮我们生成一个hello函数来帮助我们了解neon的使用:

use neon::prelude::*;

fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
    Ok(cx.string("hello node"))
}
fn main(mut cx: ModuleContext) -> NeonResult<()> {
    cx.export_function("hello", hello)?;
    Ok(())
}

如上代码所示,首先定义了一个hello函数,这里输入参数为node运行环境的上下文ctx,也就是context,hello函数的返回值是neon库中的结构体jsResult包裹的字符串数据,意思就是说返回一个javascript字符串,在编写完了hello函数之后,需要在main函数中进行编译以及注册,将hello函数注册到目前项目下的node模块中。然后我们在当前项目目录下运行node命令,首先通过require获取我们注册的hello函数,然后调用,便会输出hello node

在这个过程中,我们使用rust语言,借助于rust语言提供的内存安全保障,可以有助于我们开发出“内存安全”的nodejs模块,同时性能也不会损失太多。

调用系统借口

接下来还有一个调用rust系统层面的库,来访问系统借口的示例:

use neon::prelude::*;

fn get_num_cpus(mut cx: FunctionContext) -> JsResult<JsNumber> {
    Ok(cx.number(num_cpus::get() as f64))
}

#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
    // cx.export_function("hello", hello)?;
    cx.export_function("get_num_cpus", get_num_cpus)?;
    Ok(())
}

上面的函数中我们定义了一个查询系统核心数的函数,通过rust的num_cpus库,来访问系统借口,获取系统信息,运行之后,可以在nodejs命令后看到我们电脑cpu的核心数量。

sql以及异步

github.com/neon-bindin…这是neon官方对于sqlite操作以及rust的异步操作

SQLite提供了一个同步任务的调用接口。这意味着在执行查询时当前线程将会被阻塞。在理想的情况下,JavaScript可以将能够与查询执行同时继续执行。 而异步 SQLite 示例演示了一种将数据库操作移动到单独线程并在操作完成后异步回调的 JavaScript 的模式。由于 SQLite 自身就是单线程的,因此应用程序在查询数据库时不会受益于线程池或连接池。相反,会生成一个Rust线程来执行数据库操作。生成数据库线程后,JavaScript 主线程需要一种与它进行通信的方法。于是就创建了一个多生产者单消费者 (mpsc)的通道。接收端由数据库线程拥有,发送端由 JavaScript 持有,这样通过rust保证了线程间的安全。