iT邦幫忙

2025 iThome 鐵人賽

DAY 26
2
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 26

Day 26 - Dedicated Worker 讓重運算不再卡畫面

  • 分享至 

  • xImage
  •  

如果你曾在前端執行過一段「重運算」的程式(例如圖片壓縮、音訊處理、大量 JSON 解析),大概都有過這樣的經驗:

點下去之後整個頁面卡住,滑鼠動不了、按鈕也點不下去。

這不是瀏覽器壞掉,而是 JavaScript 是單執行緒(Single Thread)語言 的特性。

前兩天我們認識了能「掌控整個網站層級」的 Service Worker,今天我要來介紹專注於「單頁任務」的 Dedicated Worker。💪


Service Worker vs Dedicated Worker

Service Worker 和 Dedicated Worker 都屬於 Web Workers,但它們負責的任務與作用範圍不一樣。

特性 Service Worker Dedicated Worker
執行範圍 網域層級(多頁共享) 單一頁面專屬
主要用途 離線快取、攔截請求、推播通知 背景計算、資料處理
能否操作 DOM ❌ 否 ❌ 否
能否攔截網路請求 ✅ 可透過 fetch event ❌ 不行
與主執行緒溝通方式 postMessage() postMessage()
建立方式 navigator.serviceWorker.register() new Worker()

可以這樣理解:

Dedicated Worker:單頁助理,幫一個頁面處理重任務。
Service Worker:守門員,幫整個網站攔截與快取請求。


為什麼需要 Dedicated Worker?

JavaScript 的執行環境(例如瀏覽器中的主執行緒)同時負責:

  • 畫面渲染(Render)
  • 使用者事件處理(Click、Scroll...)
  • 程式邏輯執行(for 迴圈、API 請求)

當你在主執行緒執行一個耗時任務時,例如:

// 模擬重運算
for (let i = 0; i < 1e9; i++) {}
console.log('done');

這段迴圈會完全阻塞畫面,因為瀏覽器「只能等它跑完」。

Dedicated Worker 的出現,就是為了把這種「重活」丟給別的執行緒做。


Dedicated Worker 是什麼?

  • Dedicated Worker 是 Web Worker 的一種,也是 在背景執行 JavaScript 的執行緒
  • 專屬於建立它的那個頁面(主執行緒),無法被其他分頁或頁面共享。
  • 不會干擾主執行緒的 UI,也不能直接操作 DOM。
  • 主執行緒與 Worker 之間透過 message passing(訊息傳遞) 來互相溝通。

可以想像成:

主執行緒:畫面、互動、邏輯
Worker:負責重運算、資料處理


建立第一個 Dedicated Worker

1. 建立 worker.js

// worker.js
self.onmessage = function (event) {
  const num = event.data;
  let result = 0;
  for (let i = 0; i < num; i++) result += i;
  postMessage(result);
};

2. 在主執行緒中呼叫

// main.js
const worker = new Worker('./worker.js');

worker.postMessage(1e8); // 傳入資料

worker.onmessage = function (event) {
  console.log('結果:', event.data);
};

注意:Worker 檔案必須從伺服器載入(file:// 無法執行),建議用 local server 測試。

當你執行這段程式時,畫面不會卡住,但仍能在背景計算完成後得到結果。


傳遞資料的方式

Worker 與主執行緒透過 postMessage() 傳遞資料,並在另一端用 onmessage 接收。

worker.postMessage({ task: 'add', numbers: [1, 2, 3] });

worker.onmessage = (e) => console.log('結果:', e.data);

資料會以 Structured Clone(深層拷貝) 傳遞,不是參考。
因此如果資料量很大,建議使用 Transferable Objects

const buffer = new ArrayBuffer(1024);

// 第二個參數 [buffer] 表示「轉移這個物件的所有權」
worker.postMessage(buffer, [buffer]);

這樣可直接「轉移」記憶體所有權,避免不必要的拷貝。
轉移後,主執行緒的 buffer 將變為不可用,因為它的記憶體已交給 Worker。

一般物件用 Structured Clone 足夠,但若要傳大型影像或二進位資料,就該改用 Transferable Objects。


Worker 的限制

  • 跑在獨立執行環境中,與主執行緒分離,不具備瀏覽器畫面的上下文(context),無法操作 DOM、window、document。
  • 雖然沒有畫面,仍能使用不依賴 UI 的瀏覽器 API(fetch、WebSocket、IndexedDB 等 API)。
  • 可用 importScripts() 載入外部腳本,或在支援的環境使用 ES Module Worker
  • 不會自動結束,需手動釋放:worker.terminate()

實務應用場景

場景 說明
圖片壓縮/轉檔 上傳前先在背景壓縮,減少主執行緒負擔,避免畫面卡頓。
大量 JSON 處理 將解析、比對或過濾等重運算交給 Worker,讓頁面保持流暢。
AI 推論/WebAssembly 適合高運算量任務,如模型預測、影音編碼,可分離執行避免凍結。
Canvas 繪製任務分割 搭配 OffscreenCanvas 在背景繪圖,主執行緒專心維持互動流暢(還記得 Day 6 - Canvas API 效能最佳化 提過的優化技巧 - 背景執行緒繪製嗎~ 😇)。

延伸:目前的使用狀況

若說 Service Worker 是前端世界的「守門員」,那 Dedicated Worker 就是幕後的「運算引擎」 —— 不搶鏡頭,卻讓整個系統順暢運轉。兩者分工不同,缺一不可。

  • Service Worker 幾乎已成為標配:離線快取、推播通知、背景同步、PWA 等都少不了它。各大框架(Next.js、Vite、CRA、SvelteKit)皆內建支援。
  • Dedicated Worker 雖不如前者顯眼,但在許多大型 Web 應用中(如 Figma、Google Docs、影像編輯器、AI 模型推論)都被大量使用。任何需要避免主執行緒卡頓的複雜任務——它都在背後默默分擔負載。

支援與定位

  • 瀏覽器支援:兩者都獲得主流瀏覽器完整支援(Chrome、Edge、Firefox、Safari、Opera)。
  • 職責差異:Service Worker 負責「網路層控制」,Dedicated Worker 負責「運算層效能」。

Service Worker 讓網站更「聰明」(離線、快取、推播)
Dedicated Worker 讓網站更「順暢」(複雜運算不卡頓)
一個優化使用者體驗,一個優化運算效能——兩者共同構成現代 Web 的雙核心引擎。


小結

Dedicated Worker 讓前端能真正「多工」:主執行緒負責互動,Worker 負責計算,各司其職、互不干擾。

明天(Day 27),我們將進一步介紹 SharedWorker —— 能被多個分頁共享的進階版本,看看它如何讓多頁面資料同步、節省資源。🔥


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 25 - Service Worker 快取策略與更新陷阱
下一篇
Day 27 - SharedWorker 讓多分頁共享同一個執行緒
系列文
從 Canvas 到各式各樣的 Web API 之旅30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言