我目前有一个使用papaparse与React/Typescript堆栈的CSV解析应用程序,我正试图卸载一些工作的web工作者。我在这个文件中设置了worker:
import { parseFunc } from '../src/parsing'
const exported = {
parseFunc,
}
export type ParseWorker = typeof exports
expose(exported)
以及关联的tsconfig。
{
"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是如此困难。
我在我使用相同设置(React + TypeScript + Comlink)的一个项目中遇到了同样的问题。模块加载在Web Workers中的工作方式略有不同,所以你不能像平常那样使用import和export。
幸运的是,Google提供了一个名为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内核并行化工作负载,这很有用。如果这对你的用例来说是多余的,你也可以在单例模式下使用Comlink Loader。这样每个模块就有一个Web Worker。
注2:类的构造函数和任何方法都需要等待,因为它们已经被封装在异步方法中。
注意3:如果你的csvData
变量的内容很大,你可能想使用Comlink.transfer
来防止重复数据的开销。
最后,但这是我个人的观察,我在浏览器中使用Web worker的经验只是一般。我希望卸载cpu繁重的代码以提高性能并减少UI中的延迟,它确实做到了。但它也让用户界面"紧张不安"。有时,有时"停滞不前"。整个窗户。也许它们在服务器端NodeJS环境下工作得更好。不确定. .