【译】Node js 12的新功能将会颠覆人工智能,物联网和更多令人惊讶的领域(二)

译接上文

支持多线程?怎么做到的?

这个新特性仍处在试验阶段 —— 还不能在生产环境中使用。但我们还是可以随意玩玩的。那从哪开始呢?

从 Node 12 开始及至更高版本中,我们不再需要使用特定的特性标志 –experimental-workerWorker 将是默认激活的!

node index.js

现在我们可以充分利用 worker_threads 模块。让我们先写一个简单的带有两个方法的 HTTP 服务器:

  • GET /hello(返回带有“Hello World”信息的 JSON 对象)。
  • GET /compute(使用一个同步方法重复加载一个大 JSON 文件)。
const express = require('express');
const fs = require('fs');
const app = express();
app.get('/hello', (req, res) => {
  res.json({
    message: 'Hello world!'
  })
});
app.get('/compute', (req, res) => {
  let json = {};
  for (let i=0;i<100;i++) {
    json = JSON.parse(fs.readFileSync('./big-file.json', 'utf8'));
  }
  json.data.sort((a, b) => a.index - b.index);
  res.json({
    message: 'done'
  })
});
app.listen(3000);

这段代码的运行结果很容易预测。当 GET /compute/hello 被同时调用,我们必须等到 compute 调用完成才能从 hello 得到响应。事件循环被阻塞,直到文件加载完成。

让我们用多线程优化一下吧!

const express = require('express');
const fs = require('fs');
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
  console.log("Spawn http server");
  const app = express();
  app.get('/hello', (req, res) => {
    res.json({
      message: 'Hello world!'
    })
  });
  app.get('/compute', (req, res) => {
    const worker = new Worker(__filename, {workerData: null});
    worker.on('message', (msg) => {
      res.json({
        message: 'done'
      });
    })
    worker.on('error', console.error);
	  worker.on('exit', (code) => {
		if(code != 0)
          console.error(new Error(`Worker stopped with exit code ${code}`))
    });
  });
  app.listen(3000);
} else {
  let json = {};
  for (let i=0;i<100;i++) {
    json = JSON.parse(fs.readFileSync('./big-file.json', 'utf8'));
  }
  json.data.sort((a, b) => a.index - b.index);
  parentPort.postMessage({});
}

很明显,这种语法和我们所知道的 Node.js 集群扩展非常相似。但从这儿就开始变得有趣起来了。

你可以试着同时调用两个路径。注意到什么了吗?。没错,事件循环不再被阻塞,这样我们就能在文件加载期间调用 /hello 了。

现在,这就是我们都翘首以盼的东西!剩下的就是等待稳定版本的 API 出炉了。

渴望更多的 Node.js 新特性?这个 N-API 能够构建 C/C++ 模块!

Node.js 的原生运行速度正是我们青睐这个技术的原因之一。Worker threads 将会更进一步地提升 Node.js 的速度。但仅仅是这样就够了吗?

Node.js 是一种基于 C 语言的技术。当然了,我们把 JavaScript 当作一个主要编程语言来使用。但如果我们能用 C 语言做更加复杂的计算呢?

Node.js 10 版本给我们带来了 N-API。这是一个标准化的 API,适用于原生模块,让用 C/C++ 甚至是 Rust 语言构建模块成为可能。听起来很棒,对吧?

用 C/C++ 构建 Node.js 原生模块变得更加容易。

下面是一个很简单的原生模块示例:

#include <napi.h>
#include <math.h>
namespace helloworld {
    Napi::Value Method(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        return Napi::String::New(env, "hello world");
    }
    Napi::Object Init(Napi::Env env, Napi::Object exports) {
        exports.Set(Napi::String::New(env, "hello"),
                    Napi::Function::New(env, Method));
        return exports;
    }
    NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
}

如果你有 C++ 的基础,写一个自定义模块肯定不费吹灰之力。你只需记得在模块结尾将 C++ 的类型转化为 Node.js 类型即可。

接下来我们需要绑定(binding):

{
    "targets": [
        {
            "target_name": "helloworld",
            "sources": [ "hello-world.cpp"],
            "include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
            "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
            "defines": [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
        }
    ]
}

这个简单的配置让我们能够构建 *.cpp 文件,以便于后续在 Node.js 应用中使用。

在用于 JavaScript 代码之前,我们必须进行构建并配置 package.json 文件来查找 gyp 文件(绑定文件)。

{
  "name": "n-api-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "install": "node-gyp rebuild"
  },
  "gypfile": true,
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "node-addon-api": "^1.5.0",
    "node-gyp": "^3.8.0"
  }
}

当模块准备就绪,我们就可以用 node-gyp rebuild 命令进行构建并导入到 JavaScript 代码中。用法和其他流行的模块的用法一样!

const addon = require('./build/Release/helloworld.node');
console.log(addon.hello());

N-API 以及 Worker threads 赋予我们功能强大的工具,帮我们构建高性能的应用。不用说 API 或仪表板 —— 即使是复杂的数据处理或者机器学习系统都将垂手可得。多么棒啊!

Node.js 会全面支持 HTTP/2 吗?当然了!何乐不为?

我们能够计算得更快。我们能进行分布式计算。那么资源和页面服务方面表现如何?

多年来,我们一直都卡在优秀却陈旧的 http 模块和 HTTP/1.1 上没有进步。随着服务器要提供的资源越来越多,我们越来越受制于加载所花费的时间。针对每个服务器或代理服务器,各个浏览器都有个并发持久连接数上限,特别是 HTTP/1.1 协议下。有了对 HTTP/2 的支持,我们就可以和这个问题吻别了。

那我们该从哪里下手呢?你是否还记得网上每个教程中都会出现的这个 Node.js 基础示例?对,就是这个:

const http = require('http');
http.createServer(function (req, res) {
  res.write('Hello World!');
  res.end();
}).listen(3000);

在 Node.js 10 版本中,有一个崭新的 http2 模块可以让我们使用 HTTP/2.0!可算是迎来了 HTTP/2.0!

const http = require('http2');
const fs = require('fs');
const options = {
  key: fs.readFileSync('example.key'),
  cert: fs.readFileSync('example.crt')
 };
http.createSecureServer(options, function (req, res) {
  res.write('Hello World!');
  res.end();
}).listen(3000);

我们心心念念的就是 Node.js 10 版本中全面支持的 HTTP/2。

这些新特性会让 Node.js 的未来一片光明

Node.js 的新特性为我们的技术生态注入了新鲜血液。它们给 Node.js 插上翅膀,让它飞向新的天地。你想到过这个技术有一天会用于图像识别或者数据科学吗?我也从来没有想到过。

这个版本的 Node.js 还带来了更多的人们期盼已久的特性,例如对 ES 模块的支持(虽然仍出于试验阶段);又如 fs 方法的更新,终于让我们能够脱离回调地狱、拥抱 Promise 天堂了。

在下面的折线图中,我们可以发现,经过历年的增长,Node.js 的人气在 2017 年早期达到了巅峰。这并不是增长开始缓慢的迹象,而是标志着这个技术的成熟。

在这里插入图片描述

不论如何,我能够清晰地看出,所有这些新的改进和 Node.js 区块链应用(基于 truffle.js 框架)的走红,或可进一步推动 Node.js 的发展,让 Node.js 在新型的项目、角色和环境中梅开二度。

TSH(The Software House)Node.js 团队非常期待 2020 年的到来!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值