Chrome extension: 熬過了那些歷歷在目的千辛萬苦,我最後終於獲得了一些 event page 的小知識

難得用一下類輕小說標題,真的有夠長…

話說從頭

我在去讀 doc 的第一天就看到了下面這段 Event Pages 的介紹(來源)

Event pages are available in the stable channel as of Chrome 22, and the performance advantages are significant, especially on low-power devices. Please prefer them to persistent background pages whenever possible for new development and begin migrating existing background pages to this new model.

於是我就一股惱的直接栽進 event page 裡啦~~~

官方文件

官方文件裡面用了為數不少的 load, loaded 等詞,來敘述 event page 的載入狀態,但就我個人經過實驗後的理解,其實官方文件所謂的 loaded 狀態是有玄妙的。

也因此閱讀官方文件讓我感到相當迷惑。

如果你覺得下面寫得不夠清楚,你也可以直接閱讀官方文件

  • Event page 是靠事件觸發,唯一主動載入是在剛安裝的時候,而此時可以利用 runtime.onInstalled 事件來做一些每次更新版本的初始化動作(比如說加按鈕到網頁上的右鍵選單裡)

  • 每次載入 event page 都應該去 register 想要反應的事件

  • Event page 在 extension 剛安裝的時候會自動載入一次,此後只在有事件觸發它時會載入

  • Event page 的事件 listener 都應該保留在 context 的最上層 scope,以確保 event page 有 register 的事件發生時能確實觸發 handler

/* 標準寫法 */

function browserActionClickHanlder () {
  console.log('It works!');
}
chrome.browserAction.onClicked.addListener(browserActionClickHandler);
  • Event page 觸發後把事情做完,過個幾秒就會又進入休息狀態(suspend)

  • Event page 在一些條件下是不會 suspend 的:

    • message port 沒有關
    • 有可見的 view(popup window之類的) 還沒有關閉
  • 可以利用 runtime.onSuspendruntime.onSuspendCanceled 來做休息前的處理工作

  • 想要像 background page 一樣的保存狀態,必須要用 localStorageIndexedDB

我的 event page 筆記

下面創造幾個詞,用 斜體 表示:

  • event page load: 指「載入 event page」這件事(n.)
  • load event page: 指「載入 event page」的動作(v.)
  • event page loaded: 指「 event page 已經載入」的狀態(n.)
  • event page lifetime: 指「載入後的 event page 還沒有 suspend」的期間(n.)

所謂的 load event page 是重新執行一遍而不單單是喚醒並執行 event listener

這句話適用官方文件內關於 event page 所有的 loadloaded

看看下面這段簡單的 code

/* file: event_page.js */

var now = new Date();
localStorage.eventPageLoaded = now;

// 只是為了利用 browserAction 來觸發 event page load
function browserActionClickHandler () {}
chrome.browserAction.onClicked.addListener(browserActionClickHandler);

載入到 Chrome 後可以發現, 每次點擊 extension 的 icon,localStorage.eventPageLoaded 都會更新 (可以在 Chrome DevTools 的 “Resource” 頁觀察到)。

只有 top level scope 的 addListener() 動作才能夠觸發 event page load

以上面的 event_page.js 中的 browserActionClickHandler() 為例,我們試圖即時的加一個 listener 到 tabs.onUpdated 事件上。

function browserActionClickHandler () {
  chrome.tabs.onUpdated.addListener(tabsUpdatedHandler);
}

function tabsUpdatedHandler () {
  // do something when tabs update
}

實際上這個 tabsUpdatedHandler() 只能夠活過當次的 event page lifetime,在 suspend 之後,它無法觸發 event page load

其實 top level scope 的 addListener 也可以這樣寫

可以這樣寫,會正常觸發 event page load

function browserActionClickHandler (tab) {}

chrome.browserAction.onClicked.addListener(function (tab) {
  browserActionClickHandler(tab);
});

但在那個 anonymous listener function 裡,browserActionClickHandler() 只能是在第一行要執行的指令。

下面這樣寫就完全不會觸發 event page load (沒有 load event page 表示連 localStorage.browserActionClick 都不會有值)。

function browserActionClickHandler (tab) {}

chrome.browserAction.onClicked.addListener(function (tab) {
  localStorage.browserActionClick = new Date();
  browserActionClickHandler(tab);
});

event pagewindows.create 新視窗之後沒有關掉它, event page 還是 suspend

官方文件是說

Additionally, the event page will not unload until all visible views (for example, popup windows) are closed and all message ports are closed.

沒有明講所謂 visible views 到底是什麼範疇。

我用 windows.create 生了一個 popup window,沒有關閉的情況下, event page 還是 suspend 了。

目前最可靠的讓它保持 event page loaded 的方法

是使用 long-lived connections

想要保持 event page loaded 的原因是我希望我在 runtime register 的一些其它 event listenter (一旦 event page lifetime 結束就無效了的那種)能在一些狀態下保持作用。 我只需要靠狀態來控制 connection 的開關即可適時讓 event page 回到 suspend

搞這麼複雜為什麼還要用 event page ?

既然官方文件都這麼建議了…

不覺得用 event page 寫比較潮嗎。

mad-men-bad-mens-fashion-3.jpg (圖片來源: http://menscologneandperfumeforwomen.com/)