反动土著工人
React Introduct 的真实线程 . Web Worker - style API, 由单独的 API 支持 赫尔墨斯在自己的线条上运行时间——带有结构化的杂音信息,计时器, 共享内存, 和完整的本地模块访问.
React Industrial 运行您的 JavaScript 在一个 JS 线索上,并驱动 UI 从它更新。 长剖面、大图像过滤器或紧凑的模拟循环 屏蔽线程——所以它不能发送更新和您的UI摊位.
这个图书馆给你一个真实的:
import { Worker } from '@ammarahmed/react-native-workers';
const worker = new Worker({
inline: `self.onmessage = (e) => self.postMessage({ doubled: e.data * 2 });`,
});
worker.onmessage = (e) => console.log(e.data); // { doubled: 42 }
worker.postMessage(21);
无头回放原生:没有UI,但相同的JavaScript引擎,相同 计时器和保证, 以及您已经使用的本地模块 .
为什么不一样
| 真正的线程 | 它自己的赫尔墨斯跑步时间 与它自己的堆积和事件循环, 而不是你的时间一线. |
| 本地模块工作 | TurboModules, 遗留模块和硝基模块都在工人内部解决—— react-native-mmkv, (中文(简体) ), react-native-blob-util 而朋友的工作没有改变. |
| 共享记忆, 不只是消息 | 梯子从 postMessage 以锁定自由共享单元格和原始共享 ArrayBuffer选择你想付出的代价. |
| 双向RPC | 像当地人一样叫他们越过边界 async 函数,双向,使用一个共享类型. |
| 小捆 | 工人捆绑船由~150 KB来代替~1.4 MB,因为React Industrial的UI半部从未入图. |
| 可调试 | 每个工人都是自己的DevTools目标——断点、踩出和 console.log 转发给东道主 [Worker:name] 标签. |
工人与工人
这些比较很多,所以简短地说,它们解决了不同的问题,而不是 竞争者:
- 单位不同. 工作间就是 函数 加上它抓获的关闭,移动
进入另一个运行时间。 工人是个 文件 有了自己的地铁捆绑图,所以你
importnpm 包通常没有关闭- 抓取规则可以学习 . - 两个都给你真正的JS运行时间. 工作运行时间有事件循环和计时器 bundle Mode 也允许您导入库。 那个部分不是 差别.
- API不同. 工人们会说网络语谱——
new Worker(), (中文(简体) ),postMessage, (中文(简体) ),onmessage工作表对于安排工作来说是一种较低层次的必要原始内容 运行时间,它更灵活,更不熟悉. - 对于动画和手势,使用再动画 / Worklets. 他们同步的UI 运行时间是专为驾驶UI而建造的并经过战斗测试的60-120英尺。 A 类 传递消息的工人不应该是你的动画层.
- 为了"把这份工作从我的JS线上解开" 工人很合身. 解析、加密、图像 工作、数据库访问、网络I/O——每个工人本地模块实例 发生在工人身上的事件.
长的版本,包括前面的 Worklets 和他们的团队的改正, 位于 比较。 。 。 .
安装
npm install @ammarahmed/react-native-workers
要求 新建筑 与 赫尔墨斯 (RN 0.81.4+,针对
0.86 (英语). 本地代码自动链接; 运行 pod install (原始内容存档于2018-03-31). On iOS.
然后包好你的地铁配置——这就是工人的小捆绑:
const { getDefaultConfig } = require('@react-native/metro-config');
const { withWorkers } = require('@ammarahmed/react-native-workers/metro');
module.exports = withWorkers(getDefaultConfig(__dirname));
完整的设置——包括基于文件的工人的 Babel 插件和一次性 Android本地模块注册——正在 安装指南。 。 。 .
参观
档案工作者 ——自动捆绑,各出一幅地铁图
将 Babel 插件添加到 babel.config.js,然后相对引用一个文件:
const worker = new Worker('./workers/heavy-task');
每个条目都汇编成自己的捆绑——从Metro开发中获取,
以 Hermes 字节码 资产装入发布 。 见
捆绑指南
财务报告和审定财务报表 design-docs/release-bundling.md。 。 。 .
工人内部的本地模块
C++(Cxx)模块和被窝工人默认工作. 平台(Java/ObjC) 模块是每个工人选择的,因为每个工人建造涡轮模块 管理器成本内存 :
const worker = new Worker('./workers/task', { nativeModules: true });
-
iOS系统 ——每个工人
RCTTurboModuleManager解决已注册的 ObjC 模块。 应用程序不变 . -
机器人 注册您的软件包一次,因为没有全球注册:
reactHost.addReactInstanceEventListener(object : ReactInstanceEventListener { override fun onReactContextInitialized(context: ReactContext) { if (context is ReactApplicationContext) { WorkerTurboModules.initialize(context, PackageList(this@MainApplication).packages) } } })
RN的核心模块(SourceCode, (中文(简体) ), PlatformConstants, (中文(简体) ), DeviceInfo添加(...)
自动。 UI-Affine模块(UIManager and friends)被排除在外.
细节。 。 。 .
土著活动 —— 说 NativeEventEmitter 在工人中
// inside a worker
const emitter = new NativeEventEmitter(someNativeModule);
const sub = emitter.addListener('SomeEvent', (payload) => {
// fires on the worker thread
});
联合国 劳动者的 模块—— C++、 Java 或 ObjC —— 交付
直接去找那个工人 永远不要碰应用的运行时间 联合国提出事件
东道主 (应用程序是自己的) DeviceEventEmitter,或主机拥有的模块)
向登记了听众的工人转交.
细节。 。 。 .
共享状态 —— 说 SharedStore, (中文(简体) ), SharedValue, (中文(简体) ), SharedBuffer
SharedStore 是一个C++支持的商店,由宿主和每个工人共享,拥有
同步读取/写入和更改监视器 :
const store = new SharedStore('session');
store.set('user', { id: 1, name: 'Ada' });
const off = store.subscribe('user', (key, value) => { /* any runtime wrote */ });
与 postMessage,存储值是一个可地址的树——读取并更新
组件 在那棵树上,你应当观察一棵树
store.setIn('doc', ['user', 'age'], 31); // encodes only the new leaf
store.subscribeIn('doc', ['user'], (path, value) => { /* ['age'], 31 */ });
对于热道,有两个更瘦的原始人:
// A single synchronous cell — lock-free for numbers (~17M writes/sec).
const progress = new SharedValue('anim:progress', 0);
progress.value = 0.42;
// Raw shared memory — same bytes in every runtime, zero host calls per element.
const buf = new SharedBuffer('sim', 50_000 * Float64Array.BYTES_PER_ELEMENT);
const view = new Float64Array(buf.arrayBuffer);
SharedValue 是~2×比 SharedStore 单一价值; SharedBuffer
对大块数字工作来说,是~4x更快的。 整个梯子,有基准,在
design-docs/shared-data-primitives.md。 。 。 .
输入的 RPC - 那个 JSModule 桥梁和 defineModule
划过工人边界,好像是本地人 async 函数—— a
双向JS-JS RPC:
// worker (JSModule is a global in every worker)
new JSModule('calc', {
add(a, b) { return a + b; },
async fetchUser(id) { return await load(id); },
});
// host — fully typed
const calc = worker.module<Calc>('calc');
await worker.ready('calc');
const sum = await calc.add(2, 3); // 5
工人可以召回主机 模块发出事件 和大型抛物
最好通过 SharedStore 而不是每个调用克隆.
defineModule 把桥和反应状态叠成一个合同
执行下列部分:
export const calc = defineModule<{
worker: { add(a: number, b: number): number };
host: { getConfig(): Config };
events: { progress: { percent: number } };
state: { status: 'idle' | 'busy' };
}>('calc');
设计和电线协议 : design-docs/jsmodule-bridge.md, (中文(简体) ),
design-docs/jsmodule-defineModule.md。 。 。 .
UIWorker - 一个UI线上的工人
一个在月台主线上工作的非光谱工人 可以打电话
UI-Affine本土方法无线跳. 与 API 相同 Worker; 支持在
两个平台。 节制使用——这里的工作与渲染竞争.
const w = new UIWorker({ inline: `self.onmessage = (e) => { /* UI-thread JS */ };` });
从本地代码
工人可以在任何线程上通过 C++ 创建和驱动
cpp/api/NativeWorkers.h (JSON信息桥) -
对本地事件引发的联署材料背景有用.
套装大小
每个工人都是自己的地铁图 所以 import … from 'react-native' 拉开
整个框架——渲染器,组件,动画,虚拟化列表——入到每个
工人到达它。 第三方本地模块 导入桶本身,
如此小心的工人代码 独自无法避免它.
withWorkers() 决定 react-native 对一个工人大小的shim 内部工人
只有图表。在示例应用程序(Hermes bytecode,已修改)上测量:
| 劳动者 | 无 | 与 |
|---|---|---|
react-native-gzip (遗产单元) | 1.39 甲基溴 | 149个KB |
react-native-mmkv (尼特罗) | 1.42 甲基溴 | 302 KB (韩语) |
react-native-blob-util (图尔博摩多尔语) | 1.50甲基溴 | 264 KB (韩语) |
| 一个没有进口的工人 | 17.8 KB 电话 | 17.8 KB 电话 |
工人不能使用的出口(View, (中文(简体) ), StyleSheet, (中文(简体) ), Animated钩子... )
使用信件命名导出, 而不是保持沉默 undefined。 。 。 .
支持的东西
结构克隆(对象、阵列、周期、打入的阵列、, ArrayBuffer, (中文(简体) ), Date, (中文(简体) ),
Map, (中文(简体) ), Set, (中文(简体) ), RegExp, (中文(简体) ), Error, (中文(简体) ), BigInt, (中文(简体) ), self 编号 : postMessage 编号 : onmessage 编号 :
close 编号 : addEventListener计时者,应许者, structuredClone,错误
传播到 onerror, (中文(简体) ), terminate工人隔离,以及 NativeEventEmitter。 。 。 .
二进制数据传输而不是复制 : postMessage(v, [buf]) 移动
支持商店,以及 createTransferableBuffer(n) 给你一个缓冲器
每跳一个零副本.
工人内部的本地模块 单独 他们的活动被送到 而不是在应用的运行时间和复制回,他们 机构从工人的JS线(Android)中脱落 给工人自己的情况。 一个工人的网络I/O不依赖于RN JS 线是自由的.
在一个工人内部: 展览模块 通过 requireNativeModule(...) 两者
平台,以及实验
Thread
API用于在另一个线上运行工人自己的运行时间.
限制值得知道. 赫尔墨斯没有 ArrayBuffer 调离,所以调离
缓冲器不会被引擎中去子化——这个库拒绝再利用,而且
.detached 报告 true,但原始读取仍然成功,除非你打电话
enableTransferGuard()。 。 。 . SharedArrayBuffer 赫尔墨斯不存在;
SharedBuffer 是共享记忆路径。 土著单元隔离
关于私人反动 土著内部, 全部列出—— 是什么让我
删除它们——在
套接字和兼容接字。 。 。 .
示例应用程序
这个 example/ app是一个工作屏幕的画廊——搜索服务,
图像过滤、下载、传感器、平行解析、注释——加上符合性
覆盖 API 表面的套件 。 每个屏幕的分步积分都在
教程。 。 。 .
捐款
许可证
麻省理工学院 Ammar Ahmed