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

戴夫塔普斯卡
Dave Tapuska

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

Chrome 致力於加快瀏覽速度。即時瀏覽技術包括向後/轉送快取 (電腦版 Chrome 96 中出貨) 和推測規則 (在 Chrome 103 版出貨) 可改善使用前和往後的體驗。在這篇文章中,我們將探索我們對瀏覽器擴充功能 API 所做的更新,以配合這些新的工作流程。

瞭解網頁類型

在往返快取和預先算繪之前,個別分頁只有一個有效頁面。而是一律顯示在畫面上。如果使用者返回上一頁,則使用中的網頁會遭到刪除 (網頁 B),且記錄中的上一頁 (網頁 A) 會徹底重建。擴充功能無需擔心生命週期頁面有哪些部分,因為分頁只有一個標籤,即啟用/顯示狀態。

有效網頁已移除
移除使用中的網頁。

透過反向/轉送快取和預先算繪,分頁和頁面之間已不具有一對一關係。現在,每個分頁實際上會在狀態之間儲存多個頁面和頁面轉場效果,而不會被刪除再重新建構。

舉例來說,頁面可能會開始做為預先算繪 (未顯示) 的頁面,在使用者點選連結時轉換成使用中 (可見) 的頁面,然後在使用者前往其他頁面時儲存在往返快取中 (不會顯示),而這些頁面都不會遭到刪除。本文稍後將會介紹公開的新屬性,以便擴充功能瞭解處於哪些狀態頁面。

網頁類型
網頁類型。

請注意,一個分頁可以包含一系列預先算繪頁面 (不只是一個頁面)、一個「有效」 (可見) 頁面,以及一系列的返回/轉送快取頁面。

擴充功能開發人員會受到什麼影響?

FrameId == 0

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

假設最外框 frameId 為 0 的擴充功能作者可能會發生問題 (這是先前的最佳做法)。由於分頁現在可以有多個外層影格 (預先轉譯和快取頁面),因此系統會假設分頁有一個最外側的影格不正確。frameId == 0 仍會繼續顯示「使用中」頁面的最外頁框,但同一分頁中「其他」頁面的最外影格都不會是零。為解決這個問題,我們新增了 frameType 欄位。請參閱本文的「如何判斷影格是否位於最外框?」一節。

影格與文件的生命週期

另一個因擴充功能而有問題的概念,就是影格的生命週期。頁框負責代管文件 (與修訂版本網址相關聯)。 文件可以變更 (例如透過瀏覽),但 frameId 不會改變,因此很難將特定文件中發生的事件與 frameIds 建立關聯。我們引進了 documentId 的概念,這是每個文件的專屬 ID。瀏覽影格並開啟新文件後,ID 就會變更。這個欄位適合用來判斷頁面何時變更其生命週期狀態 (在預先轉譯/啟用/快取之間),因為這個欄位維持不變。

網頁導覽事件

chrome.webNavigation 命名空間中的事件可能會根據所在的生命週期,在同一頁面中多次觸發。請參閱「如何判斷網頁目前的生命週期?」和「如何判斷網頁轉換的時間?」這兩節。

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

針對先前可使用 frameId 的多個擴充功能 API,新增 DocumentLifecycle 類型。如果事件 (例如 onCommitted) 出現 DocumentLifecycle 類型,此類型的值就是產生事件的狀態。您隨時可以透過 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 合併,並判斷影格是否為使用中的最外層影格。例如:js 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 群組提問。