我有一个场景,用户可能会快速产生事件(例如悬停)。每次悬停都会向网络工作人员发送一条消息以进行一些计算。 每条新消息都应取消前一条消息,并且我需要确保仅处理最后一条消息并将其结果返回到 UI 线程。
如何确保 Web Worker 仅处理它收到的最后一条消息? 我想避免任何去抖时间,因为延迟最小化很重要。
我创建了 NPM 包 @wjfe/async-workers,它提供了一个名为
CancellationSource
的类。 此类使用 SharedArrayBuffer
将取消任务的愿望传输给 Web Worker,无需函数生成器或异步编程。 您只需在 FOR 循环中使用 CancellationSource.throwIfSignaled()
即可取消。
这个类可以单独使用,但我建议您使用
AsyncWorker
类,因为它简化了传递缓冲区的麻烦,并且还为整个 Web Worker 使用提供了一个很好的异步语法。
一个例子:
// myWorker.ts
import { CancellationSource, workerListener, type PostFn, type Token } from "@wjfe/async-workers";
export const myWorker = {
calculate(payload: Payload, _: PostFn, cancelToken: Token): MyData {
for (let i = 0; i < someCap; ++i) {
CancellationSource.throwIfSignaled();
// Calculate
}
return result;
};
export type MyWorker = typeof myWorker;
self.onMessage = workerListener(myWorker);
然后在UI线程中:
// user-file.ts
import { myWorker } from "myWorker.js";
const worker = getWorkerSomehowDependingOnYourToolingSuchAsVite();
const controller = new AsyncWorker(worker, myWorker);
现在您可以使用
controller
来启动工作:
// somewhere.ts
let workItem: WorkItem | undefined;
myElement.addEventListener('hover', () => {
workItem?.cancel();
workItem = controller.enqueue.calculate(undefined, { cancellable: true });
});
或者类似的东西。 请遵循存储库的自述文件以获得更高的准确性。
您在上面看到的是一个事件侦听器,它将首先取消之前的工作项,然后在每次事件触发时生成一个新的工作项。
重要:为此,您必须满足跨域隔离的条件。