大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
1.什么是 Napa.jsNapa.js 是一个基于 V8 构建的多线程 JavaScript 运行时,最初设计用于在 Bing 中开发具有优秀性能的高度迭代服务。 后面逐渐意识到 Napa.js 可以在 CPU 密集型任务中作为 Node.js 的有效补充,并能够在多个 V8 隔离中执行 JavaScript 并在它们之间进行通信。
Napa.js 作为 Node.js 模块公开,同时它也可以嵌入到主机进程中(host process)而无需依赖 Node.js。
Napa.js: a multi-threaded JavaScript runtime
Napa.js 具有以下特点:
多线程 JavaScript 运行时具有 NPM 支持的 Node.js 兼容模块架构用于跨 JavaScript 线程进行对象传输、对象共享和同步的 API用于可插入日志记录、指标和内存分配器的 API作为 Node.js 模块分发,并支持嵌入场景目前 Napa.js 在 Github 通过 MIT 协议开源,有超过 9.2k 的 star、是一个值得关注的前端开源项目。
2.Napa.js 的多线程架构接下来一起谈谈 napa.js 的多线程架构。
Napa.js 有一个称为区域(zone)的概念,一个 zone 可以执行指定的代码块,但是同一个 zone 不能执行多个代码块,这种情况需要创建多个 zone。 一个 zone 由多个 Javascript worker 组成,每个 worker 都是一个不同的线程。
在一个 zone 内,所有 worker 都是对称的,即加载相同代码,以无法区分的方式提供广播服务和执行请求,而且开发者不能要求 zone 在特定 worker 线程上执行代码。 而不同 zone 的 worker 是不对称的,即加载不同的代码或者加载相同的代码但强化不同的策略,例如:堆大小、安全设置等。应用程序可能需要多个 zone 来处理不同目的或不同策略的工作负载。
同时,一个进程可能包含多个 zone, Napa.js 中有两种类型的 zone,每种 zone 都有特定的特征:
Napa zone :由 Napa.js 管理的 JavaScript worker(V8 隔离)组成,可以是多个但每个可以包含多个 worker, Napa zone 的 Worker 支持部分 Node.JS API。Node zone : 公开 Node.js 事件循环的 “虚拟(virtual)” 区域,可以访问完整的 Node.js 功能。Napa.js 中的每个 worker 线程都管理自己的堆空间,将值从一个 worker 传递到另一个 worker 必须进行序列化 / 反序列化。值得关注的是以下两个核心操作:
Broadcast: 运行更改所有 worker 状态的代码,返回挂起操作的 Promise。 通过 promise 只能知道操作是成功还是失败。 通常使用 Broadcast 来引导应用程序、预缓存对象或更改应用程序设置。execute : 运行代码,不会更改任意 worker 的状态,并返回获得结果的 Promise。 执行是为完成实际工作而设计的。zone 操作遵循先到先服务的原则,而广播的优先级高于执行。以下代码演示了广播和执行如何协作来完成一个简单的任务:
function foo() { console.log('hi');}// 这会在区域中的所有 worker 中设置 foo 的函数定义zone.broadcast(foo.toString());// 在任意 worker 线程上执行函数 foo zone.execute(() => { global.foo() });除了 execute 外,开发者还可以使用 Store API 在 worker 之间共享数据。 每次执行此操作时,数据都会复制到每个线程的堆空间。 但 Napa.js 未来计划实现不同的内存共享模式,以便在 worker 之间共享数据而无需复制,这些内存共享模式最终将成为 JavaScript 中高性能多线程解决方案的基石。
napa.js 的整体架构如下:
以上架构可以使得开发者能够使用 Napa zone 进行繁重的工作,并使用 Node zone 进行 IO,Node zone 还弥补了 Napa zone 对 Node API 支持不完整的缺陷。
3.如何使用 Napa.js首先需要安装:
npm install napajs接着可以按照如下方式使用 Napa.js:
const napa = require('napajs');const zone1 = napa.zone.create('zone1', { workers: 4});// 向 “zone1” 中的所有 4 个 worker 广播代码zone1.broadcast('console.log("hello world");');// 在 “zone1” 中的任何 worker 中执行匿名函数zone1.execute( (text) => text, ['hello napa']) .then((result) => { console.log(result.value); });Napa.js 还引入了 Store API 作为跨 JavaScript worker 共享可传输类型的必要补充。 在 store.set 期间,值被设置为 JSON 并存储在进程堆中,因此所有线程都可以访问它,并在用户通过 store.get 检索它们时解组。
以下代码演示了使用 Storage 进行 worker 线程对象共享的示例:
var napa = require('napajs');var zone = napa.zone.create('zone1');var store = napa.store.create('store1');// Set 'key1' in node.store.set('key1', { a: 1, b: "2", c: napa.memory.crtAllocator // transportable complex type.};// Get 'key1' in another thread.zone.execute(() => { var store = global.napa.store.get('store1'); console.log(store.get('key1'));});4.本文总结本文主要和大家介绍 Napa.js ,其是一个基于 V8 构建的多线程 JavaScript 运行时,最初设计用于在 Bing 中开发具有优秀性能的高度迭代服务。因为篇幅问题,关于 Napa.js 只是做了一个简短的介绍,但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。
参考资料https://www.youtube.com/watch?v=-JE8P2TiJEg
https://github.com/microsoft/napajs
https://github.com/Microsoft/napajs/wiki/build-napa.js
https://github.com/Microsoft/napajs/wiki/introduction
https://www.linkedin.com/pulse/napajs-multi-threaded-javascript-runtime-daiyi-peng
https://dev.to/arealesramirez/is-node-js-single-threaded-or-multi-threaded-and-why-ab1
https://www.freecodecamp.org/news/javascript-asynchronous-operations-in-the-browser/