簡體   English   中英

在 Web-Worker 中同步等待消息

[英]Synchronously Wait for Message in Web-Worker

有什么方法可以同步等待或檢查網絡工作者中的新消息嗎?

我有大量復雜的代碼(從 emscripten 編譯的 LLVM),我無法圍繞回調進行重構。

我需要確保在我收到並處理來自 UI 線程的消息之前,某一行之后的代碼不會執行。 如果我用 while 循環阻塞,事件循環永遠不會運行,所以我無法接收消息。

這是我在使用Pyodide時也遇到的問題。 我想從主線程“同步”調用一個函數。

一種解決方案涉及AtomicSharedArrayBuffer API。 從 web worker 的角度來看,這看起來像下面這樣

  1. postMessage主線程
  2. Atomics.wait凍結我們自己
  3. 被主線程解凍
  4. SharedArrayBuffer讀取結果。 我們無法以postMessage的形式接收結果,因為沒有一種同步方式來詢問“我收到消息了嗎”。

當然,這需要相當多的額外代碼來處理所有的序列化、數據傳遞等等。

主要限制是要使用這些 API,需要設置 COOP/COEP 標頭 要記住的另一點是,這只適用於最近的瀏覽器,例如 Safari 15.2(2021 年 12 月發布)。

還有一個帶有同步 XHR 和 service worker的替代解決方案,但我還沒有研究過這個選項。

一個粗略的破解方法可能是使用同步 API,例如 FileSystem API,並使用臨時文件作為同步機制。

在您的示例中,emscripten 代碼可以對文件發出同步讀取,而 UI 線程寫入同一個文件,從而有效地解除阻塞工作人員。

不,不幸的是。 有一些關於添加一種方法來阻止來自父頁面的消息的討論,但它沒有成功。 我會看看我是否可以挖掘相關的郵件列表線程。

你能在不重構的情況下打破如下順序嗎?

wrk.onmessage = function(e) {
    if (e.data.step === 'initial input') {
        doInitialWork(e.data.inputs)
    } else if (e.data.step === 'ui input') {
        doTheRest(e.data.uiData)
    }
}

onmessage 事件將被阻止,直到初始步驟執行堆棧完成,並且關鍵 ui 位僅在信息可用時啟動。

我就是這樣做的。 想到 Web Workers 還沒有收到await 消息功能,真的很可悲,這將使整個線程間通信概念更接近例如Go語言。 但是不,他們沒有這樣做,所以必須發明一些東西來保持線程同步

  let resolver: any = undefined;
  let message: any = undefined;
  const messagePromise = new Promise((resolve) => resolver = resolve);

  worker.onmessage = async ({ data: payload }: { data: any }) => {
    message = payload;
    worker.onmessage = undefined;
    resolver?.();
  }

  await messagePromise;

現在,這是打字稿。 只需刪除類型即可獲取 Javascript。 請注意,如果在我們開始偵聽消息之前已發送消息,則無法捕獲該消息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM