WebWorker 即將被取代!JS 發(fā)布全新 API
背景
首先,簡單介紹一下背景。我們正在開發(fā)一個基于 Vue3 的項目,客戶習慣通過多個瀏覽器標簽頁同時打開相同的項目,這樣可以輕松地操作多個頁面。比如,客戶會這樣操作(雖然這只是一個簡化的例子,實際情況可能是兩個非常不同的頁面):
圖片
這種做法其實可以理解,因為一些客戶不喜歡頻繁地在同一標簽頁內(nèi)切換菜單,他們認為這樣太麻煩了。
盡管這兩個頁面的布局和內(nèi)容差異很大,但有一部分內(nèi)容其實是相似的(雖然它們有所不同,因此沒有封裝成獨立組件)。
圖片
這部分相似的邏輯是依賴同一個接口和相同的數(shù)據(jù)處理邏輯的,而且這兩個過程都需要花費比較長的時間:
- 接口請求: 需要大約3000ms,因為后端數(shù)據(jù)獲取邏輯比較復雜,而且返回的數(shù)據(jù)量也很大。
- 數(shù)據(jù)處理: 大約300ms,前端拿到數(shù)據(jù)后還需要進行處理。
因此,客戶提出了一個建議:既然這兩部分內(nèi)容的邏輯是一樣的,能否讓多個頁面(比如頁面二、頁面三、頁面四)共享頁面一的數(shù)據(jù)呢?
分析與優(yōu)化
在客戶提出優(yōu)化需求之前,我們先從優(yōu)化點的角度來考慮一下。
接口請求和數(shù)據(jù)處理這兩個過程都是比較耗時且涉及大數(shù)據(jù)量的操作。一開始,我的思路是嘗試使用 WebWorker 來處理這些任務(wù)。
但是,客戶的建議讓我意識到 WebWorker 并不適用,原因如下:
- 每個標簽頁的 WebWorker 是獨立的,不能共享數(shù)據(jù)。
- 即便使用 WebWorker 和 IndexedDB 來緩存數(shù)據(jù)并嘗試共享,但依然很難共享數(shù)據(jù)的狀態(tài)。
第一個原因大家可能都理解。第二個原因則需要進一步解釋:為什么數(shù)據(jù)狀態(tài)共享如此重要呢?
我們可以通過下圖來理解這個問題。為了讓頁面二、頁面三、頁面四能夠知道頁面一的數(shù)據(jù)狀態(tài),數(shù)據(jù)的狀態(tài)管理就變得至關(guān)重要??梢园褦?shù)據(jù)狀態(tài)理解為類似于 Promise 的三種狀態(tài):未緩存、緩存中和已緩存。
圖片
舉個例子來說明兩種可能的情況:
圖片
- 情況一: 頁面一加載后點擊按鈕發(fā)起數(shù)據(jù)請求并進行緩存,接著再點擊頁面二的按鈕。此時,頁面二應(yīng)該能直接使用頁面一的緩存數(shù)據(jù),這種情況就沒有問題。
- 情況二: 頁面一點擊按鈕1秒后,用戶點擊了頁面二的按鈕。此時,頁面二并不知道頁面一的數(shù)據(jù)狀態(tài),無法判斷是否需要發(fā)起新的請求,或者應(yīng)該等待頁面一的請求完成。
因此,共享數(shù)據(jù)狀態(tài)顯得尤為重要。
SharedWorker
經(jīng)過分析,我決定放棄 WebWorker 的方案,改用 SharedWorker 來實現(xiàn)數(shù)據(jù)共享。
圖片
SharedWorker 是什么呢?它可以被理解為類似于 WebWorker,但有一個關(guān)鍵的不同點:SharedWorker 允許多個標簽頁共享,而 WebWorker 每個標簽頁都獨立。
當多個標簽頁連接同一個 SharedWorker 時,SharedWorker 會通過port管理每個標簽頁,每個標簽頁對應(yīng)一個port。這樣,通過 SharedWorker,多個標簽頁可以共享數(shù)據(jù)。
為了說明 SharedWorker 的工作原理,下面是一個簡單的例子,演示如何通過 SharedWorker 實現(xiàn)多個頁面間的count共享。
圖片
圖片
如上圖所示,count變量在多個標簽頁間共享。
圖片
接下來,我們修改shared-worker.js中的邏輯,讓其負責數(shù)據(jù)請求和處理:
圖片
圖片
然而,經(jīng)過測試,我們發(fā)現(xiàn)目前的實現(xiàn)并沒有達到預期的效果!雖然共享了count數(shù)據(jù),但如果我們按順序點擊頁面一和頁面二,數(shù)據(jù)并不會同時出現(xiàn),反而出現(xiàn)了請求重復的情況,這樣并沒有優(yōu)化到位。
解決方案
此時,我們意識到需要實現(xiàn)數(shù)據(jù)狀態(tài)共享,這可以通過利用 Promise 來完成。通過 Promise,頁面可以等待數(shù)據(jù)請求和處理完成,然后再進行后續(xù)的操作。
圖片
最終效果如下:
圖片
這樣,即使用戶沒有同時點擊頁面一和頁面二,只要頁面一的數(shù)據(jù)請求和處理完成,頁面二也能同時獲取到已經(jīng)緩存的數(shù)據(jù)。
通過這種方式,我們成功地實現(xiàn)了多個頁面之間的數(shù)據(jù)共享,并且保證了數(shù)據(jù)狀態(tài)的同步。
























