首页 > 解决方案 > 如何让童工与多个工人一起向 Deno 中的父母发送消息?

问题描述

我是工人新手,所以基于这个问题,我尝试了以下操作:

// main.t
for(let idx = 0; idx < 4; idx++){
  const worker = new Worker(new URL('./worker.ts', import.meta.url).href, {
    type: "module", 
    deno: { namespace: true},
  });

  worker.postMessage({ id: idx, name: 'text1', email: 'ea@da.com' });
  worker.addEventListener('message', message => {
    console.log('response', message.data)
  })
}

// worker.ts
self.onmessage = async (params) => {
  const data = params.data
  console.log('params', data)
  data.name = 'text2'
  self.postMessage(data)
  self.close()
}

期待这个:

params { id: 2, name: "text1", email: "ea@da.com" }
response { id: 2, name: "text2", email: "ea@da.com" }
params { id: 0, name: "text1", email: "ea@da.com" }
response { id: 0, name: "text2", email: "ea@da.com" }
params { id: 1, name: "text1", email: "ea@da.com" }
response { id: 1, name: "text2", email: "ea@da.com" }
params { id: 3, name: "text1", email: "ea@da.com" }
response { id: 3, name: "text2", email: "ea@da.com" }

但相反,我得到的是:

params { id: 0, name: "text1", email: "ea@da.com" }
params { id: 1, name: "text1", email: "ea@da.com" }
params { id: 2, name: "text1", email: "ea@da.com" }
params { id: 3, name: "text1", email: "ea@da.com" }
response { id: 3, name: "text2", email: "ea@da.com" }

有人可以帮我解决我哪里出错了吗?为什么我只得到最后一个工人的回应,而不是得到每个工人的回应?

标签: web-workerdeno

解决方案


有人可以帮我解决我哪里出错了吗?为什么我只得到最后一个工人的回应,而不是得到每个工人的回应?

我怀疑这是因为您在postMessage完成之前关闭了每个工人。在你的worker.ts

self.postMessage(data)
self.close()

从 MDN 页面DedicatedWorkerGlobalScope.close()

接口的close()方法丢弃在's 事件循环中排队的任何任务,有效地关闭了这个特定的范围。DedicatedWorkerGlobalScopeDedicatedWorkerGlobalScope

下面,我对您的示例进行了重构,增加了一些类型安全性和更详细的日志记录,以便您可以查看更多事件和一些时间信息。在示例中,不是self.close()从每个工作人员内部调用,而是Worker.terminate()在接收到每条消息后(在我们完成工作人员之后)在主范围的消息事件处理程序中调用。您可以忽略三斜杠指令(尽管它们可能有助于在您的编辑器中进行类型检查)。

util.ts

export type ExampleData = {
  sender: string;
  timestamp: number;
};

export function formatMessage (
  direction: 'in' | 'out',
  callerName: string,
  interlocutorName: string,
  timestamp: number,
): string {
  // 7 === Math.max('receive'.length, 'post'.length);
  const directionString = (direction === 'in' ? 'receive' : 'post').padEnd(7);
  // 8 === Math.max('worker n'.length, 'main'.length);
  return `${(callerName).padEnd(8)}  ${directionString}  ${(interlocutorName).padEnd(8)}  ${timestamp}`;
}

worker.ts

/// <reference no-default-lib="true" />
/// <reference lib="deno.worker" />

import {ExampleData, formatMessage} from './util.ts';

function handleMessageEvent (ev: MessageEvent<ExampleData>): void {
  console.log(formatMessage('in', self.name, ev.data.sender, ev.data.timestamp));

  const data: ExampleData = {sender: self.name, timestamp: Date.now()};
  self.postMessage(data);
  console.log(formatMessage('out', self.name, ev.data.sender, data.timestamp));
}

self.addEventListener('message', handleMessageEvent);

main.ts

// /// <reference lib="deno.unstable" />

import {ExampleData, formatMessage} from './util.ts';

function handleMessageEvent (this: Worker, ev: MessageEvent<ExampleData>): void {
  console.log(formatMessage('in', 'main', ev.data.sender, ev.data.timestamp), '✅');
  this.terminate();
}

// initialize static data once outside the loop
const specifier = new URL('./worker.ts', import.meta.url).href;
const options: WorkerOptions = {
  type: 'module',
  // deno: {namespace: true}, // requires deno run --unstable
};

for (let idx = 0; idx < 4; idx += 1) {
  const workerName = `worker ${idx}`;
  const worker = new Worker(specifier, {...options, name: workerName});

  // in testing this example, registering the event listener after posting
  // the first message didn't seem to chnage behavior, however it's safer to
  // register before posting in order to ensure that registation happens
  // prior to the event generated by the response
  worker.addEventListener('message', handleMessageEvent);

  const data: ExampleData = {sender: 'main', timestamp: Date.now()};
  worker.postMessage(data);
  console.log(formatMessage('out', 'main', workerName, data.timestamp));
}

运行示例:

/home/jesse/worker-example$ deno run --allow-read=. main.ts
Check file:///home/jesse/worker-example/main.ts
main      post     worker 0  1627390801087
Check file:///home/jesse/worker-example/worker.ts
main      post     worker 1  1627390801104
Check file:///home/jesse/worker-example/worker.ts
main      post     worker 2  1627390801122
Check file:///home/jesse/worker-example/worker.ts
main      post     worker 3  1627390801144
Check file:///home/jesse/worker-example/worker.ts
worker 0  receive  main      1627390801087
worker 0  post     main      1627390801776
main      receive  worker 0  1627390801776 ✅
worker 1  receive  main      1627390801104
main      receive  worker 1  1627390801811 ✅
worker 1  post     main      1627390801811
worker 3  receive  main      1627390801144
main      receive  worker 3  1627390801873 ✅
worker 3  post     main      1627390801873
worker 2  receive  main      1627390801122
worker 2  post     main      1627390801875
main      receive  worker 2  1627390801875 ✅


推荐阅读