🚧 — Worker
API 仍處於實驗階段,不應視為已準備好投入生產。
Worker
讓您可以在與主執行緒共用 I/O 資源的情況下,啟動並與在獨立執行緒上執行的全新 JavaScript 執行個體進行通訊。
Bun 實作了一個最小的 Web Workers API 版本,並附有擴充功能,使其更適合於伺服器端使用案例。與 Bun 的其他部分一樣,Bun 中的 Worker
支援 CommonJS、ES 模組、TypeScript、JSX、TSX 等,而且開箱即用。無需額外的建置步驟。
建立 Worker
與瀏覽器中一樣,Worker
是全域性的。使用它來建立新的工作人員執行緒。
來自主執行緒
const workerURL = new URL("worker.ts", import.meta.url).href;
const worker = new Worker(workerURL);
worker.postMessage("hello");
worker.onmessage = event => {
console.log(event.data);
};
工作人員執行緒
// prevents TS errors
declare var self: Worker;
self.onmessage = (event: MessageEvent) => {
console.log(event.data);
postMessage("world");
};
若要防止在使用 self
時出現 TypeScript 錯誤,請將此行新增至工作人員檔案的最上方。
declare var self: Worker;
您可以在工作人員程式碼中使用 import
和 export
語法。與瀏覽器不同,無需指定 {type: "module"}
即可使用 ES 模組。
為了簡化錯誤處理,在呼叫 new Worker(url)
時會解析要載入的初始指令碼。
const worker = new Worker("/not-found.js");
// throws an error immediately
傳遞給 Worker
的指定符會相對於專案根目錄解析(例如輸入 bun ./path/to/file.js
)。
"open"
當工作執行緒建立並準備好接收訊息時,會發出 "open"
事件。這可以用於在工作執行緒準備好後,傳送第一個訊息給工作執行緒。(瀏覽器中不存在此事件。)
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.addEventListener("open", () => {
console.log("worker is ready");
});
訊息會自動排隊,直到工作執行緒準備好為止,因此不需要等到 "open"
事件才能傳送訊息。
使用 postMessage
傳送訊息
若要傳送訊息,請使用 worker.postMessage
和 self.postMessage
。這會利用 HTML 結構化複製演算法。
// On the worker thread, `postMessage` is automatically "routed" to the parent thread.
postMessage({ hello: "world" });
// On the main thread
worker.postMessage({ hello: "world" });
若要接收訊息,請在工作執行緒和主執行緒上使用 message
事件處理常式。
// Worker thread:
self.addEventListener("message", event => {
console.log(event.data);
});
// or use the setter:
// self.onmessage = fn
// if on the main thread
worker.addEventListener("message", event => {
console.log(event.data);
});
// or use the setter:
// worker.onmessage = fn
終止工作執行緒
當 Worker
執行緒的事件迴圈沒有工作可做時,Worker
執行緒會自動終止。在全域或任何 MessagePort
上附加 "message"
監聽器,將會使事件迴圈保持運作。若要強制終止 Worker
,請呼叫 worker.terminate()
。
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
// ...some time later
worker.terminate();
這會導致工作執行緒盡快退出。
process.exit()
工作執行緒可以使用 process.exit()
自行終止。這不會終止主程序。與 Node.js 類似,process.on('beforeExit', callback)
和 process.on('exit', callback)
會在工作執行緒上發出(而不是在主執行緒上發出),而結束代碼會傳遞給 "close"
事件。
"close"
當工作執行緒終止時,會發出 "close"
事件。工作執行緒實際終止可能需要一些時間,因此此事件會在工作執行緒標記為已終止時發出。CloseEvent
會包含傳遞給 process.exit()
的結束代碼,或者如果因為其他原因而關閉,則為 0。
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.addEventListener("close", event => {
console.log("worker is being closed");
});
瀏覽器中不存在此事件。
管理生命週期
預設情況下,一個 active 的 Worker
會讓主程式 (spawning) 保持運作,因此非同步任務,例如 setTimeout
和 promises,會讓程式保持運作。附加 message
監聽器也會讓 Worker
保持運作。
worker.unref()
若要停止正在執行的 worker 讓程式保持運作,請呼叫 worker.unref()
。這會將 worker 的生命週期與主程式的生命週期分開,等同於 Node.js 的 worker_threads
所做的動作。
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.unref();
注意:worker.unref()
在瀏覽器中不可用。
worker.ref()
若要讓程式保持運作直到 Worker
終止,請呼叫 worker.ref()
。ref'd worker 是預設行為,且仍需要在事件迴圈中進行某些動作 (例如 "message"
監聽器),才能讓 worker 繼續執行。
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.unref();
// later...
worker.ref();
或者,你也可以將 options
物件傳遞給 Worker
const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
ref: false,
});
注意:worker.ref()
在瀏覽器中不可用。
使用 smol
的記憶體使用量
JavaScript 執行個體會使用大量記憶體。Bun 的 Worker
支援 smol
模式,可減少記憶體使用量,但會犧牲效能。若要啟用 smol
模式,請將 smol: true
傳遞給 Worker
建構函式中的 options
物件。
const worker = new Worker("./i-am-smol.ts", {
smol: true,
});
smol
模式實際上做了什麼?