![]()
2015年,一位前端工程師在GitHub issue里寫下:「計算斐波那契數列時,頁面凍結了3秒,用戶以為瀏覽器崩潰了。」這條issue獲得了1400多個,卻等了9年才等到一個像樣的答案。JavaScript的單線程模型像一條設計精良的單行道——異步I/O開得飛快,CPU密集型任務卻堵成停車場。
Worker API(工作線程接口)理論上能解決問題,但用起來像在沒有導航的陌生城市開車。你需要手動創建腳本文件、處理消息傳遞、管理線程生命周期,還要小心閉包陷阱。一個40行的計算任務,配套代碼能寫到200行。社區統計過,npm上帶「worker」關鍵詞的封裝庫超過800個,說明這不是某個人的痛點,是整個生態的集體妥協。
從「能跑就行」到「像寫同步代碼」
今年4月發布的puru庫把這段代碼:
const worker = new Worker('./fib.js');worker.postMessage(40);worker.onmessage = ({ data }) => console.log(data);
壓縮成了一行:
const { result } = spawn(() => fibonacci(40));
表面看是語法糖,實際重構了心智模型。開發者不再需要把邏輯拆到另一個文件,不需要手寫消息協議,甚至不需要理解Transferable Objects(可傳輸對象)的內存規則。puru在編譯階段把函數序列化,注入到Worker沙箱里執行,再把結果Promise化返回。
這個設計有個刻意為之的限制:函數不能捕獲外部閉包。乍看是缺陷,實則是防呆機制——它強迫你意識到Worker運行在隔離上下文,共享狀態會出bug。很多開發者第一次用Worker時,都踩過「閉包變量突然變成undefined」的坑。puru用編譯時錯誤替代了運行時驚喜。
當Promise.all()不夠用的時候
CPU密集型任務很少單打獨斗。圖像處理要流水線,科學計算要分片,數據分析要MapReduce。Promise.all()能并發,但管不了背壓、超時、取消信號——這些在服務端是基本功,在瀏覽器里得自己造輪子。
puru從Go語言借了chan()和WaitGroup(等待組)兩個原語。看這段生產者-消費者模型:
const input = chan(50);const output = chan(50);for (let i = 0; i < 4; i++) { spawn(async ({ input, output }) => { for await (const n of input) { await output.send(n * 2); } });}
通道在這里充當機械緩沖,解耦了生產速度和消費速度。50的緩沖區意味著生產者最多領先消費者50個任務,超出的部分會阻塞等待——這是顯式的背壓控制,raw Worker(原生工作線程)里完全沒有。但緩沖區大小沒有銀彈:太小會頻繁阻塞,太大可能內存溢出。puru把這個權衡留給開發者,文檔里建議「根據任務粒度和可用內存測試調整」。
序列化的代價與邊界
不是所有函數都能塞進spawn()。puru使用structured clone algorithm(結構化克隆算法)序列化參數和函數體,這意味著你不能傳DOM節點、不能傳函數引用、不能傳循環引用的對象。一個試圖在Worker里操作canvas的開發者會收到清晰的報錯,而不是靜默失敗。
這個限制劃清了適用邊界:puru適合純計算任務(加密、壓縮、矩陣運算),不適合需要頻繁與主線程交互的場景。游戲引擎的物理模擬、視頻編輯器的實時預覽,這些需要每幀同步的狀態,Worker通信開銷會吃掉所有收益。
庫的維護者在README里寫得很誠實:「這不是Worker的替代品,是80%場景的默認選擇。」剩下的20%,你仍然需要掌握Transferable Objects和SharedArrayBuffer(共享內存緩沖區)。
為什么現在才出現
Worker API 2010年就進了草案,2014年全瀏覽器支持。14年里,社區不是沒有嘗試過封裝——從早期的webworker-threads到近年的comlink,每個都解決了一部分問題。但comlink主打的是「讓Worker像代理對象」,仍然要求你把邏輯拆到單獨文件;puru第一次做到了「寫在哪就在哪運行」。
這個突破依賴兩個基礎設施成熟:ES Module(ECMAScript模塊)讓動態加載不需要全局污染,Top-level await(頂層等待)讓異步初始化不再丑陋。2020年前的JavaScript寫不出puru這樣的API。
npm周下載量從發布時的300漲到現在的4700,增速曲線像早期webpack。但更重要的信號是生態位——Vite團隊正在評估內置集成,Deno(一個JavaScript運行時)的第三方注冊表已經收錄。一個庫有沒有未來,不看star數,看構建工具愿不愿意背書。
puru的GitHub倉庫里有個被置頂的討論串:「你們會支持WASM(WebAssembly)互操作嗎?」維護者的回復是:「有計劃,但想先觀察社區怎么用通道模式。」這個回答本身說明了一件事——他們還沒想清楚邊界在哪里,但愿意跟著真實需求走,而不是畫路線圖。
下一個版本會砍掉什么功能,又會因為什么用戶反饋加回來?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.