![]()
JavaScript 統治前端開發15年,但一個老問題始終沒解決:CPU 密集型任務會讓頁面直接卡死。算個斐波那契數列,主線程就凍結,用戶體驗瞬間歸零。
Worker 線程(網頁多線程技術)本該是解藥,但原生 API 寫起來像在做手工活——創建文件、發消息、收消息、手動同步。一個簡單計算要拆成三四個文件,心智負擔極高。
GitHub 上有個叫 puru 的庫,把這套流程壓到了5行代碼。不是語法糖,是把線程管理的機械復雜度整個抽走了。
原生 Worker 的"手工活"困境
算第40個斐波那契數,原生寫法要先建一個 fib.js 文件,里面放計算邏輯。主線程創建 Worker 實例,postMessage 發參數,onmessage 等結果。
三個步驟,兩個文件,消息來回一趟。代碼量不多,但上下文切換頻繁——你剛在主線程寫業務邏輯,突然要切到另一個文件里想線程通信的邊界問題。
puru 的做法是直接傳函數:spawn(() => fibonacci(40)),然后 await 結果。函數被自動序列化到 Worker 里執行,開發者不用碰文件系統。
這個抽象有個硬性代價:函數不能捕獲外部變量。閉包里的數據傳不進去,因為 Worker 是進程級隔離,不是線程級共享。puru 把這個限制擺到明面上,反而避免了隱蔽的狀態共享 bug。
結構化并發:從 Promise.all 到生產級流水線
Promise.all 能并行多個異步任務,但遇到 CPU 密集型流水線就露怯了。四個 Worker 同時消費數據,怎么協調輸入輸出?怎么防止死鎖?怎么控制內存不爆?
puru 搬來了 Go 語言的 channel 和 WaitGroup。channel 是帶緩沖的隊列,生產者往里塞,消費者往外取,中間有背壓機制——緩沖區滿了就阻塞,不會無限堆積。
代碼長這樣:先建兩個 channel,一個輸入一個輸出,各50個緩沖位。然后循環 spawn 四個 Worker,每個從輸入 channel 取數,平方后送進輸出 channel。
緩沖大小是開發者自己定的。太小會頻繁阻塞,太大吃內存。puru 不替你猜,把權衡暴露出來,這和 Rust 的顯式錯誤處理一個路數。
不是銀彈,但填補了生態空白
沒有這類工具,JS 開發者只有兩條路:要么忍受主線程卡頓,要么自己造輪子。前者產品體驗差,后者維護成本高。
puru 的約束很清晰:函數序列化、無閉包、手動調緩沖。這些不是缺陷,是 Worker 模型的物理限制被翻譯成了 API 設計。
項目還在早期,但解決的是一個真實痛點——JS 生態里缺一把趁手的 Worker 工具。不是讓多線程變簡單,是讓"簡單任務的多線程"不再復雜。
你在生產環境用過 Worker 線程嗎?最后是自己封了一套,還是干脆避開 CPU 密集型場景了?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
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.