Chrome 擴充功能:擴充 API 以支援即時導覽功能

Dave Tapuska
Dave Tapuska

重點摘要:Extensions API 已更新,以便支援往返快取,預先載入導覽。詳情如下。

Chrome 一直致力於提升瀏覽速度。即時導覽技術 (例如 往返快取,已在 Chrome 96 的電腦上推出) 和推測規則 (已在 Chrome 103 中推出) 可改善前往和返回的體驗。本文將探討我們為因應這些新工作流程而對瀏覽器擴充功能 API 所做的更新。

瞭解頁面類型

在推出往返快取和預先算繪功能之前,每個分頁只有一個有效網頁。這一直是顯示的內容。如果使用者返回上一頁,系統會刪除目前的網頁 (網頁 B),並完全重建歷史記錄中的上一頁 (網頁 A)。擴充功能不需要擔心網頁處於生命週期中的哪個階段,因為分頁只有一個狀態 (啟用/顯示)。

淘汰目前的頁面
將有效頁面逐出。

有了往返快取和預先顯示功能,分頁和網頁之間就不再是一對一關係。如今,每個分頁實際上都會儲存多個頁面,並在狀態之間進行頁面轉換,而非遭到銷毀和重建。

舉例來說,網頁一開始可能會以預先算繪 (不可見) 的形式存在,在使用者點選連結時轉換為有效 (可見) 網頁,然後在使用者瀏覽其他網頁時儲存在返回/前進快取 (不可見) 中,而不會遭到刪除。在本文稍後的部分,我們將探討公開的新屬性,協助擴充功能瞭解網頁的狀態。

頁面類型
頁面類型。

請注意,分頁可以有一系列預先算繪的網頁 (不只一個)、單一有效 (可見) 網頁,以及一系列快取的「返回」/「前進」網頁。

這對擴充功能開發人員有何影響?

FrameId == 0

在 Chromium 中,我們將最上層/主頁框稱為最外層頁框。

假設最外層框架的 frameId 為 0 (先前的最佳做法) 的擴充功能作者,可能會發生問題。由於分頁現在可以有多個最外層框架 (預先算繪和快取的網頁),因此假設分頁只有一個最外層框架的假設是不正確的。frameId == 0 仍會繼續代表有效頁面的最外層框架,但同一個分頁中其他頁面的最外層框架會設為非零值。我們已新增「frameType」frameType欄位來修正這個問題。請參閱本篇文章的「如何判斷某個影格是否為最外層影格?」一節。

影格和文件的生命週期

另一個與擴充功能相關的問題是影格生命週期。框架會代管文件 (與已提交的網址相關聯)。文件可能會變更 (例如透過導覽),但 frameId 不會變更,因此很難只透過 frameId 連結特定文件中的事件。我們正在推出 documentId 概念,這是每份文件的專屬 ID。如果導覽框架並開啟新文件,ID 就會變更。這個欄位可用於判斷網頁何時變更生命週期狀態 (在預先算繪/有效/快取之間),因為它會保持不變。

網頁導覽事件

根據生命週期,chrome.webNavigation 命名空間中的事件可以在同一個網頁上觸發多次。請參閱「如何判斷網頁處於哪個生命週期?」和「如何判斷網頁轉換時間?」兩節。

如何判斷網頁的生命週期?

DocumentLifecycle 類型已新增至先前提供 frameId 的多個擴充功能 API。如果事件中包含 DocumentLifecycle 類型 (例如 onCommitted),其值就是事件產生的狀態。您隨時可以透過 WebNavigation getFrame()getAllFrames() 方法查詢資訊,但建議您一律使用事件中的值。如果您使用這兩種方法,請注意,在事件產生和兩種方法傳回的承諾解決之間,影格狀態可能會有所變更。

DocumentLifecycle 的值如下:

  • "prerender":目前未向使用者顯示,但可能會向使用者顯示。
  • "active":目前向使用者顯示。
  • "cached":儲存在往返快取中。
  • "pending_deletion":文件正在銷毀中。

如何判斷某個影格是否為最外層影格?

先前的擴充功能可能會檢查 frameId == 0,以判斷事件是否發生在最外層框架。由於分頁中含有多個網頁,因此我們現在有多個最外層框架,因此 frameId 的定義有問題。您不會收到關於快取回溯/前進影格框架的事件。不過,對於預先算繪的框架,frameId 會為最外層框架的非零值。因此,使用 frameId == 0 做為訊號,判斷是否為最外層的框架是不正確的做法。

為協助您完成這項操作,我們推出了名為 FrameType 的新類型,讓您輕鬆判斷框架是否確實為最外層的框架。FrameType 的值如下:

  • "outermost_frame":通常稱為最上方的影格。請注意,這些項目有重複的部分。舉例來說,如果您有預先算繪及快取的網頁,每個網頁都有一個最外層的框架,可稱為最頂層的框架。
  • "fenced_frame":保留供日後使用。
  • "sub_frame":通常為 iframe。

我們可以將 DocumentLifecycleFrameType 合併,並判斷影格是否為有效的外層影格。例如:tab.documentLifecycle === “active” && frameType === “outermost_frame”

如何解決使用時間與影格相關的問題?

如上所述,框架會代管文件,且框架可能會導向新文件,但 frameId 不會變更。當您收到只包含 frameId 的事件時,就會發生問題。如果您查詢框架的網址,可能會發現該網址與事件發生時的網址不同,這稱為使用時間問題。

為解決這個問題,我們引入了 documentId (以及 parentDocumentId)。如果提供 documentIdwebNavigation.getFrame() 方法現在會讓 frameId 成為選用項目。每當導覽畫格時,documentId 就會變更。

如何判斷頁面轉換的時間?

系統會透過明確的信號,判斷網頁在不同狀態之間的轉換時間。

我們來看看 WebNavigation 事件

首次瀏覽任何網頁時,您會看到以下順序的四個事件。請注意,當 DocumentLifecycle 狀態為 "prerender""active" 時,可能會發生這四個事件。

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

下圖說明瞭這項情況,顯示預先轉譯的網頁成為有效網頁時,documentId 會變更為 "xyz"

當預先算繪的網頁成為有效網頁時,documentId 會變更
當預先算繪頁面成為有效頁面時,documentId 會變更。

當網頁從「往返快取」或「預先算繪」轉換為「有效」狀態時,系統會產生另外三個事件 (但 DocumentLifecyle"active")。

onBeforeNavigate
onCommitted
onCompleted

documentId 會與原始事件相同。如上所述,當 documentId == xyz 啟用時,就會發生這種情況。請注意,由於網頁已載入,因此除了 onDOMContentLoaded 事件外,其他相同的導覽事件都會觸發。

如有任何意見或問題,歡迎在 chromium-extensions 群組中提出。