1. 欢迎
在本实验中,您将使用现有的 Web 应用,并添加 Web 工作器以在两个打开的窗口之间共享状态。这是渐进式 Web 应用工作坊的一系列配套 Codelab 中的第八个。上一个 Codelab 是 Service Worker Includes。这是本系列中的最后一个 Codelab。
学习内容
- 在多个打开的窗口之间添加共享工作器
- 使用 Comlink 更轻松地处理工作器
注意事项
- JavaScript
所需条件
- 支持共享 Web Worker 的浏览器
2. 进行设置
首先,克隆或下载完成此 Codelab 所需的起始代码:
如果您克隆了代码库,请确保您位于 pwa06--working-with-workers
分支中。该 ZIP 文件还包含相应分支的代码。
此代码库需要 Node.js 14 或更高版本。获得代码后,在代码的文件夹中通过命令行运行 npm ci
,以安装所需的所有依赖项。然后,运行 npm start
以启动 Codelab 的开发服务器。
源代码的 README.md
文件提供了对所有分发文件的说明。此外,以下是您将在整个 Codelab 中使用的关键现有文件:
密钥文件
js/preview.js
- 预览网页 JavaScript 文件js/main.js
- 主要应用 JavaScript 文件
3. 编写 Worker
目前,Web 应用的预览功能仅在加载时显示最新内容。理想情况下,它会在用户输入时显示实时预览。这需要编译可能大量的数据,并在两个不同的打开窗口之间传输这些数据。因此,我们不希望在任何打开的窗口的主线程上执行此操作。我们改用共享 Web Worker。
首先,创建一个包含以下代码的 js/worker.js
文件:
import { expose } from 'comlink';
import { marked } from 'marked';
class Compiler {
state = {
raw: '',
compiled: '',
};
subscribers = [];
async set(content) {
this.state = {
raw: content,
compiled: marked(content),
};
await Promise.all(this.subscribers.map((s) => s(this.state)));
}
subscribe(cb) {
this.subscribers.push(cb);
}
}
const compiler = new Compiler();
onconnect = (e) => expose(compiler, e.ports[0]);
说明
此代码设置了一个名为 Compiler
的类,该类允许设置内容,并允许在编译完内容后调用订阅。由于它是共享工作器,因此只能使用此类的一个实例,所以系统会实例化 Compiler
的新实例。然后,为了让从 worker 外部使用此类时感觉顺畅,我们使用 Comlink 来公开编译器实例,从而能够像使用代码中声明的编译器实例一样使用其所有方法。由于这是一个共享工作器,而不是专用工作器,因此需要向所有连接公开。
4. 向 Worker 发送内容
创建工作器后,我们现在需要向其中发送内容。为此,请更新 js/main.js
以执行以下操作:
- 从
comlink
导入名为wrap
的导出项 - 创建一个名为
worker
的新模块型 Shared Worker,将其类型设置为module
,并使用new URL
模式 (new URL('./worker.js', import.meta.url)
) 指向该 Shared Worker - 创建一个
compiler
变量,用于对worker.port
进行wrap
- 在编辑器的更新函数 (
editor.onUpdate
) 中,将内容保存到数据库后,等待compiler.set
完成,并传入内容
说明
封装 Comlink 导出项后,公开的类方法等内容可以像未跨工作器边界共享一样使用,但现在一切都是异步的。由于这是共享工作器,而不是专用工作器,因此 Comlink 需要封装工作器的端口,而不是工作器本身。现在,每当对编辑器进行更新时,内容都会发送到工作器进行处理!
5. 更新预览页
最后一步是将编译后的内容从共享工作器中提取到预览中!实现此目的的设置大致相同,但由于函数无法在工作器边界之间传递,因此需要改用函数的代理。Comlink 再次为您提供帮助。更新 js/preview.js
以执行以下操作:
- 从
comlink
中导入名为wrap
和proxy
的导出项 - 创建并封装共享工作器,就像在
js/main.js
中一样 - 使用代理函数调用编译器的
subscribe
方法,该代理函数将传入数据的compiled
属性设置为预览区域的内部 HTML
完成后,打开预览,开始在编辑器中输入内容,然后您会惊喜地发现,Markdown 会自动神奇地编译并实时显示在预览区域中,而不会阻塞任何页面的主线程!
6. 恭喜!
您已了解如何使用共享 worker 在多个 PWA 实例之间共享状态。