将 Google Comlink 用于具有 React/Typescript 的网络工作者会导致 DOM 异常
Posted
技术标签:
【中文标题】将 Google Comlink 用于具有 React/Typescript 的网络工作者会导致 DOM 异常【英文标题】:Using Google Comlink for web workers with React/Typescript results in DOM Exception 【发布时间】:2021-12-11 09:25:38 【问题描述】:我目前有一个使用 papaparse 和 React/Typescript 堆栈的 CSV 解析应用程序,并且我正在尝试将其中一些工作卸载给网络工作者。我在这个文件中设置了工人:
import parseFunc from '../src/parsing'
const exported =
parseFunc,
export type ParseWorker = typeof exports
expose(exported)
连同关联的 tsconfig.json 在同一目录中:
"compilerOptions":
"strict": true,
"target": "esnext",
"module": "esnext",
"lib": [
"webworker",
"esnext"
],
"moduleResolution": "node",
"noUnusedLocals": true,
"sourceMap": true,
"allowJs": false,
"baseUrl": "."
然后我在这里加载并尝试运行它:
import wrap from 'comlink'
const worker = new Worker('../../../customWebWorkers',
name: 'customWebWorkers',
type: 'module',
)
const workerApi = wrap<import('../../../customWebWorkers').ParseWorker>(
worker
)
return await workerApi.parseFunc(
csvData
)
在本地运行它就可以了!当我尝试将我的应用程序推送到当前运行的版本时,问题出现了,我遇到了这个错误:
Uncaught (in promise) DOMException: Failed to construct 'Worker':
Script at 'https://myWebStorage/customWebWorkers.132234d2.chunk.worker.js'
cannot be accessed from origin 'https://csv-parser-132.com'.
at...
我在网上查看了一些替代解决方案,最常见的两个是使用 Blob 获取脚本对象的 url 并以这种方式加载它,或者使用 importScripts:不幸的是,这些似乎都不适用于我的用例。如果我尝试这些解决方案,则会收到此错误:
Failed to load module script: Expected a javascript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
我认为这是由于上述解决方案没有包含 tsconfig 文件。
我知道这是一个相当困难的问题,但任何可能的答案将不胜感激!我很惊讶在 typescript/React 堆栈中运行 web worker 如此困难。
【问题讨论】:
【参考方案1】:我在one of my projects 中遇到了同样的问题,我使用了相同的设置(React + TypeScript + Comlink)。模块加载与 Web Worker 的工作方式略有不同,因此您不能像往常一样使用导入和导出。
幸运的是,谷歌还有一个名为comlink-loader 的库可以解决这个问题。您必须将要workerize的脚本从customWebWorkers
重命名为customWebWorkers.worker.js
。 Comlink Loader 会在编译过程中自动获取它并创建一个包装类,然后您可以使用import ParseWorker from 'comlink-loader!../../../customWebWorkers'
导入它。然后,您可以像往常一样使用这个包装的类来执行您的方法。
import ParseWorker from 'comlink-loader!../../../customWebWorkers'
const workerFactory = new ParseWorker()
const worker = await new workerFactory.ParseWorker()
const result = await parseWorker.parseFunc(csvData)
注意 1:在这个例子中有两种类型的 ParseWorker
类。顶部是一个工厂,可用于创建任意数量的实例。基本上,每个实例都是其自己的 Web Worker,独立于其他实例运行,如果您想在所有 CPU 内核上并行化工作负载,这将非常有用。如果这对您的用例来说太过分了,您还可以在singleton mode 中使用 Comlink Loader。这为每个模块提供了一个 Web Worker。
注意 2:构造函数和类中的任何方法都需要等待,因为它们已被包装在异步方法中。
注意 3:如果您的 csvData
变量的内容很大,您可能需要使用 Comlink.transfer
来防止重复数据的开销。
最后,但这更多是个人观察,我在浏览器中使用 Web Workers 的经验只是马马虎虎。我希望卸载 CPU 繁重的代码以提高性能并减少 UI 中的延迟,它确实做到了.. 但它有时也使 UI “紧张”,有时“停滞”整个窗口。也许它们在服务器端 NodeJS 上下文中工作得更好.. 不确定..
【讨论】:
嘿,谢谢!正如你所说,我重新设计了所有使用 comlink 加载程序,但现在我看到了一个完全不同的问题;每当我尝试使用此错误启动它时,加载器似乎都会失败:` ./src/utils/parse.worker.ts 中的错误(./node_modules/comlink-loader/dist/comlink-worker-loader.js !./src/utils/parse.worker.ts) 33:9 模块解析失败:意外令牌 (33:9) 使用这些加载器处理文件:* ./node_modules/comlink-loader/dist/comlink-worker-loader .js`知道这是怎么回事吗?你遇到过类似的问题吗?以上是关于将 Google Comlink 用于具有 React/Typescript 的网络工作者会导致 DOM 异常的主要内容,如果未能解决你的问题,请参考以下文章