使用網路工作站在瀏覽器執行 JavaScript's 主執行緒

非主執行緒架構可以大幅改善應用程式的可靠性和使用者體驗。

蘇爾馬
Surma

過去 20 年來,網路從只有幾種樣式和圖片的靜態文件,演變成複雜的動態應用程式。不過,有很大的改變是,我們為每個瀏覽器分頁只有一個執行緒 (有一些例外),負責轉譯網站和執行 JavaScript。

導致主要執行緒過度處理。此外,隨著網頁應用程式複雜度增加,主要執行緒將成為效能的嚴重瓶頸。更糟的是,在特定使用者的主執行緒上執行程式碼所需的時間幾乎完全無法預測,因為裝置功能對效能有很大的影響。隨著使用者存取網路的裝置種類繁多,從高規格的功能型手機,到刷新率高的旗艦機等,只有越來越多元化的旗艦機,才會變得更加難以預測。

如果您希望複雜的網頁應用程式能穩定符合效能指南,例如網站體驗核心指標 (根據人類觀感和心理學方面的經驗資料),就需要透過主執行緒 (OMT) 執行程式碼。

為何需要網路工作人員?

根據預設,JavaScript 是單一執行緒語言,可在主執行緒上執行工作。不過,網路工作程式可讓開發人員啟動個別的執行緒來處理主執行緒以外的工作,以便從主執行緒提供一種逃生方法。雖然網路工作人員的範圍有限,且無法直接存取 DOM,但如果有重大工作需要處理,導致主要執行緒負擔過重,這些工作人員可能大大受益。

如果對網站體驗核心指標有疑慮,在主要執行緒中執行工作可能會很有幫助。請特別注意,將工作從主要執行緒卸載給網路工作人員,可以減少主執行緒爭用的情況,從而改善重要的回應指標,例如與下一個顯示的內容互動 (INP)首次輸入延遲時間 (FID)。如果主要執行緒的處理工作較少,就能更快回應使用者互動。

主要執行緒作業的減少 (尤其是啟動期間) 也藉由減少長時間工作,為最大內容繪製 (LCP) 帶來潛在效益。轉譯 LCP 元素時需要執行主要執行緒時間,這對於轉譯文字或圖片相當常見且常見的 LCP 元素,並且降低整體主執行緒的工作量,有助於確保網頁工作站可能改為處理昂貴的工作,避免阻礙您網頁的 LCP 元素。

與網路工作站進行執行緒

其他平台通常會支援平行工作,可讓您將執行緒函式與程式的其他部分平行執行。您可以在這兩個執行緒存取相同的變數,且這些共用資源存取權會與互斥鎖和分層同步,避免發生競爭狀況。

在 JavaScript 中,我們可從網路工作人員取得大致類似的功能,這些工具自 2007 年以來便已推出,且自 2012 年起支援所有主要瀏覽器。網路工作站會與主執行緒並行執行,但與 OS 執行緒不同,他們無法共用變數。

如要建立網路工作站,請將檔案傳送至工作站建構函式,程式開始在另一個執行緒中執行該檔案:

const worker = new Worker("./worker.js");

透過 postMessage API 傳送訊息,與網路工作站通訊。在 postMessage 呼叫中將訊息值做為參數傳遞,然後將訊息事件監聽器新增至工作站:

main.js

const worker = new Worker('./worker.js');
worker.postMessage([40, 2]);

worker.js

addEventListener('message', event => {
  const [a, b] = event.data;

  // Do stuff with the message
  // ...
});

如要將訊息傳回至主要執行緒,請在網路工作站中使用相同的 postMessage API,並在主執行緒上設定事件監聽器:

main.js

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

worker.postMessage([40, 2]);
worker.addEventListener('message', event => {
  console.log(event.data);
});

worker.js

addEventListener('message', event => {
  const [a, b] = event.data;

  // Do stuff with the message
  postMessage(a + b);
});

這種方法很有限。以往,網路工作人員主要用於將單一繁重工作移出主要執行緒。嘗試用單一網路工作站處理多項作業時,速度可能較慢:您不僅要為參數和訊息中的作業進行編碼,還得做好記帳來比對回應與要求。這可能是網路工作人員尚未廣泛採用的原因。

不過,如果我們能夠消除主要執行緒和網路工作人員之間溝通的難度,就很適合在許多用途上。好運,有程式庫能幫上忙!

Comlink 是一個程式庫,其目標在於讓您直接使用網路工作站,而不必費心思考 postMessage 的詳細資訊。Comlink 可讓您在網路工作站和主要執行緒之間共用變數,就像其他支援執行緒的程式設計語言一樣。

設定 Comlink 在網路工作站中匯入,並定義向主執行緒公開的一組函式。接著在主執行緒匯入 Comlink、包裝 worker,然後取得公開函式的存取權:

worker.js

import {expose} from 'comlink';

const api = {
  someMethod() {
    // ...
  }
}

expose(api);

main.js

import {wrap} from 'comlink';

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

主要執行緒的 api 變數行為與網路工作站中的變數相同,差別在於每個函式都會傳回一個值承諾,而非值本身。

您應該將什麼程式碼轉移到網路工作站?

網路工作站無法存取 DOM 和許多 API (例如 WebUSBWebRTCWeb Audio) ,因此您無法將需要這類存取權的應用程式部分放在工作站中。儘管如此,每移動一小段程式碼到工作站,在主執行緒上也要購買更多空間來存放「具有」特性的內容,例如更新使用者介面。

對網頁程式開發人員而言,其中一個問題就是,大多數的網頁應用程式都仰賴 Vue 或 React 等 UI 架構來自動化調度管理應用程式中的所有內容,所有項目都是架構的組成元件,因此本身也與 DOM 相關聯。這樣似乎很難遷移至 OMT 架構。

不過,如果改用模型,而該模型的 UI 問題與其他問題 (例如狀態管理) 分開,即使在架構型應用程式上,網路工作站仍能派上用場。這正是 PROXX 採取的做法。

PROXX:OMT 個案研究

Google Chrome 團隊開發了 PROXX 做為 Minesweeper 本機副本,藉此滿足 漸進式網頁應用程式規定,包括離線作業,以及提供引人入勝的使用者體驗。不幸的是,早期版遊戲在功能型手機等受限裝置的效能不佳,導致團隊意識到主要執行緒是瓶頸。

該團隊決定使用網路工作站將遊戲的視覺狀態與邏輯區隔開來:

  • 主執行緒會處理動畫和轉換的轉譯作業。
  • 網路工作人員會處理遊戲邏輯,這單純是運算邏輯。

OMT 對 PROXX 的功能型手機效能產生了有趣的影響。在非 OMT 版本中,當使用者與使用者介面互動後,使用者介面將凍結六秒。沒有回應,使用者必須等待 6 秒過後,才能夠執行其他操作。

PROXX 的 非 OMT 版本 UI 回應時間。

在 OMT 版本中,遊戲需要 12 秒才能完成 UI 更新。雖然看來似乎有效能下滑的趨勢,但使用者反而會獲得更多意見回饋。發生緩慢的情形,是因為應用程式傳送的影格超過非 OMT 版本,而且完全不會運送任何影格。因此,使用者知道發生了什麼狀況,並可在更新 UI 時繼續玩遊戲,讓遊戲感覺更棒。

OMT PROXX 版本中的 UI 回應時間。

這種情況相當謹慎的取捨:我們為裝置受到限制的使用者提供了更好的體驗,讓他們在不干擾高階裝置使用者的情況下享有更好的體驗

OMT 架構的影響

如 PROXX 的例子所示,OMT 能讓應用程式在更多裝置上穩定執行,但無法加快應用程式執行速度:

  • 您只是從主執行緒移動工作,而非減少工作。
  • 網路工作站和主要執行緒之間的額外通訊負擔,有時可能會使作業速度稍微變慢。

考量優缺點

由於主要執行緒在 JavaScript 執行時可以自由處理捲動等使用者互動,因此即使總等待時間可能較長,但影格遺失的影格也較少。鼓勵使用者等待一小段時間時,最好捨棄影格,因為捨棄影格的誤差範圍較小:捨棄影格時是以毫秒為單位發生,但出現「數百」毫秒後,使用者就會感受到等待時間。

由於各裝置的效能難以預測,所以 OMT 架構的目標是降低風險,在面臨高度變動的執行階段條件下,應用程式更穩定,而非平行處理的效能優勢。營運韌性以及改善使用者體驗,比任何在速度方面的小額權衡。

工具注意事項

網路工作人員尚未成為主流,因此大多數模組工具 (例如 webpackRollup 這類工具) 並不支援立即使用。(Parcel 卻是!)幸好,您可以使用一些外掛程式,讓網路工作人員能夠順利與 webpack 和 Rollup 服務搭配使用

總結

為確保我們盡可能提供可靠且易於存取的應用程式,尤其是在日益普及的市集中,我們必須支援有限制的裝置,因為這類裝置是全球大多數使用者存取網路的方式。OMT 可望提升這類裝置上的效能,同時不影響高階裝置的使用者。

此外,OMT 也有次要優點:

網路工作人員不必感到驚慌。Comlink 這類工具可以減輕工作人員的工作負擔,讓他們有適合用於各種網頁應用程式的選擇。

主頁橫幅來自 Unsplash,作者:James Peacock