在 Aurelia 和 TypeScript 中正确实施网络工作者
Proper implementation of web workers in Aurelia and TypeScript
遗憾的是,我在整个网络上找不到一个单一的答案。
我有一个基于 TypeScript
/ Aurelia CLI
/ RequireJS
的 Aurelia 应用程序。
结构如下:
|data
|-MyService.ts
|workers
|-SomeWorker.ts/js
存在一个名为 aurelia-pal-worker
的包,但没有文档或复杂的示例。
到目前为止我尝试了什么
Typed-Web-Workers
不错,但太局限了
- 拥有
SomeWorker
.js 并使用 Browserify 作为 aurelia_project[=59= 中的附加构建步骤].
只要我需要像 RxJs
这样的外部库,Browserify 方法就可以工作。
当然,当我尝试 require("../data/MyService.ts")
时,这会中断。为此,我需要用另一个替换整个构建管道,它使用 tsify 插件通过 Browserify 运行整个 aurelia 项目。
在我看来我有 3 个选择:
- 找到一个工作示例,将 TypeScript 文件编译为网络工作者,并使用
aurelia-pal-worker
导入依赖项。
- 使用
TypedWorker
并将昂贵的函数放入线程中,例如:
new TypedWoker(expensiveFuncFromService, handleOutput)
- 编译
MyService.ts
以分离 JS 文件(而不是捆绑它)并像这样要求它:
require("/scripts/MyService.js")
后两个好像不太吸引我,但应该很简单。非常感谢任何提示或示例!
PS:对于任何不熟悉 Aurelia 的人:它在后台使用 gulp 管道。
所以经过一番摆弄后,我切换到 webpack based solution, which allows me to use the amazing webpack-worker-loader。
这是修改我的现有项目并启动它和快速 运行 之间的最佳权衡。
最后是这样的:
custom_typings/worker-loader.d.ts
declare module "worker-loader!*" {
const content: new () => any;
export = content;
}
worker/some-service.ts
export class SomeService {
public doStuff() {
console.log("[SomeService] Stuff was done");
}
}
worker/my-worker.ts
import "rxjs/add/observable/interval";
import { Observable } from "rxjs/Observable";
import { SomeService } from "./some-service";
const svc = new SomeService();
svc.doStuff();
console.log("[Worker] Did stuff");
onmessage = event => {
console.log(event);
};
Observable.interval(1000).subscribe(x => postMessage(x));
worker加载后是这样的:
import * as MyWorker from "worker-loader!./worker/my-worker";
const worker = new MyWorker();
worker.onmessage = msg => console.log("[MyClass] got msg from worker", msg);
它将生成以下控制台输出:
1: "[SomeService] Stuff was done"
2: "[Worker] Did stuff"
3: "[MyClass] got msg from worker", 1
4: "[MyClass] got msg from worker", 2
...
您需要在 worker 中使用完整的 DI 吗?
不用担心,在 的一点帮助下,我想出了如何用我们基于 webpack 的解决方案重写它:
let container: Container = null;
let myService: SuperComplexService = null;
// Import the loader abstraction, so the DI container knows how to resolve our modules.
import("aurelia-pal-worker")
.then(pal => pal.initialize())
// We need some polyfills (like "Reflect.defineMetadata")
.then(() => import("aurelia-polyfills"))
// Then we get the DI service and create a container
.then(() => import("aurelia-dependency-injection"))
.then(({ Container }) => (container = new Container()))
.then(() => import("../services/my-super-complex-service")) // Here we go!
.then(({ SuperComplexService }) => (myService = container.get(SuperComplexService) as SuperComplexService))
.then(() => startWorker());
const startWorker = async() => {
// Let's get going!
}
此加载器链的所有功劳归于@jeremy-danyow。
遗憾的是,我在整个网络上找不到一个单一的答案。
我有一个基于 TypeScript
/ Aurelia CLI
/ RequireJS
的 Aurelia 应用程序。
结构如下:
|data
|-MyService.ts
|workers
|-SomeWorker.ts/js
存在一个名为 aurelia-pal-worker
的包,但没有文档或复杂的示例。
到目前为止我尝试了什么
Typed-Web-Workers
不错,但太局限了- 拥有
SomeWorker
.js 并使用 Browserify 作为 aurelia_project[=59= 中的附加构建步骤].
只要我需要像 RxJs
这样的外部库,Browserify 方法就可以工作。
当然,当我尝试 require("../data/MyService.ts")
时,这会中断。为此,我需要用另一个替换整个构建管道,它使用 tsify 插件通过 Browserify 运行整个 aurelia 项目。
在我看来我有 3 个选择:
- 找到一个工作示例,将 TypeScript 文件编译为网络工作者,并使用
aurelia-pal-worker
导入依赖项。 - 使用
TypedWorker
并将昂贵的函数放入线程中,例如:new TypedWoker(expensiveFuncFromService, handleOutput)
- 编译
MyService.ts
以分离 JS 文件(而不是捆绑它)并像这样要求它:
require("/scripts/MyService.js")
后两个好像不太吸引我,但应该很简单。非常感谢任何提示或示例!
PS:对于任何不熟悉 Aurelia 的人:它在后台使用 gulp 管道。
所以经过一番摆弄后,我切换到 webpack based solution, which allows me to use the amazing webpack-worker-loader。
这是修改我的现有项目并启动它和快速 运行 之间的最佳权衡。
最后是这样的:
custom_typings/worker-loader.d.ts
declare module "worker-loader!*" {
const content: new () => any;
export = content;
}
worker/some-service.ts
export class SomeService {
public doStuff() {
console.log("[SomeService] Stuff was done");
}
}
worker/my-worker.ts
import "rxjs/add/observable/interval";
import { Observable } from "rxjs/Observable";
import { SomeService } from "./some-service";
const svc = new SomeService();
svc.doStuff();
console.log("[Worker] Did stuff");
onmessage = event => {
console.log(event);
};
Observable.interval(1000).subscribe(x => postMessage(x));
worker加载后是这样的:
import * as MyWorker from "worker-loader!./worker/my-worker";
const worker = new MyWorker();
worker.onmessage = msg => console.log("[MyClass] got msg from worker", msg);
它将生成以下控制台输出:
1: "[SomeService] Stuff was done"
2: "[Worker] Did stuff"
3: "[MyClass] got msg from worker", 1
4: "[MyClass] got msg from worker", 2
...
您需要在 worker 中使用完整的 DI 吗?
不用担心,在
let container: Container = null;
let myService: SuperComplexService = null;
// Import the loader abstraction, so the DI container knows how to resolve our modules.
import("aurelia-pal-worker")
.then(pal => pal.initialize())
// We need some polyfills (like "Reflect.defineMetadata")
.then(() => import("aurelia-polyfills"))
// Then we get the DI service and create a container
.then(() => import("aurelia-dependency-injection"))
.then(({ Container }) => (container = new Container()))
.then(() => import("../services/my-super-complex-service")) // Here we go!
.then(({ SuperComplexService }) => (myService = container.get(SuperComplexService) as SuperComplexService))
.then(() => startWorker());
const startWorker = async() => {
// Let's get going!
}
此加载器链的所有功劳归于@jeremy-danyow。