monoの開発ブログ

ChromeのEvent Pagesで実現する省メモリな拡張機能

Chromeの拡張機能のリソース消費を抑える仕組みであるEvent Pagesを紹介します。

Chromeの拡張機能では、Background Pageというページを裏に常時開いておき、外からのイベントやメッセージに応じて処理を行うという構成が一般的です。すなわち、ブラウザを起動してから終了するまでの間ずっとページを開いたままということになり、拡張機能の数が増えるとプロセス数やメモリ使用量はかなりのものになります。

そこで導入されたのがEvent Pagesです。Event Pagesを利用すると、ページが常駐しなくなるため、リソース消費が削減されます。イベントやメッセージを処理する必要がある時には自動的にEvent Pageが開かれ、処理が終わってしばらくするとまた閉じられます。

導入方法

Event Pagesの仕組みは勝手に適用されるわけではなく、拡張機能側の対応が必要です。

まず、manifest.jsonに "persistent": false の記述を追加します。

{
  "background": {
    "scripts": [
      ...
    ],
    "persistent": false
  }
}

これにより、Background PageではなくEvent Pageが利用されるようになります。Event Pageになっても従来のBackground Pageと基本的には変わらないのですが、ページを閉じてしまうという性質上、そのままでは以下のような問題が生じて正しく動作しません。該当する場合には修正する必要があります。

  • onloadDOMContentLoaded がページを開き直すたびに呼び出される
  • setTimeoutsetInterval が動作しない
  • 変数やDOMを操作した内容が消えてしまう
  • chrome.extension.getBackgroundPage が使えない

他にもあるみたいですが、私の拡張機能には関係なかったので追ってません。ドキュメント見てください。

onload や DOMContentLoaded がページを開き直すたびに呼び出される

これらのイベントはページを開き直すたびに呼び出されてしまうため、従来のままでは意図したとおりに動作しません。代わりに chrome.runtime.onInstalledchrome.runtime.onStartup を利用します。

chrome.runtime.onInstalled.addListener(function() {
  // 拡張のインストール時やバージョンアップ時に呼ばれる
});
chrome.runtime.onStartup.addListener(function() {
  // ブラウザ起動時に呼ばれる
});

setTimeout や setInterval が動作しない

代わりに chrome.alarms に用意されたAPIを利用します。chrome.alarms.create で作成したアラームは、 chrome.runtime.onInstalled のタイミングで呼び出せばブラウザを終了してもそのまま有効なようです。

chrome.runtime.onInstalled.addListener(function() {
  // 5分後にイベントを発生させる (一度だけ)
  chrome.alarms.create('bar', { delayInMinutes: 5 });
  // 5分毎にイベントを発生させる
  chrome.alarms.create('foo', { periodInMinutes: 5 });
});

chrome.alarms.onAlarm.addListener(function(alarm) {
  if (alarm) {
    if (alarm.name == 'foo') {
      ...
    }
    else if (alarm.name == 'bar') {
      ...
    }
  }
});

変数やDOMを操作した内容が消えてしまう

chrome.storageやIndexedDB、localStorageなどに保存して永続化しておけば、Event Pageが閉じられても値が消えることはありません。

chrome.extension.getBackgroundPage が使えない

プロセスが落ちていると値を返すのに時間が掛かるため、非同期に動作する chrome.runtime.getBackgroundPage が追加されました。代わりにこちらを利用します。

chrome.runtime.getBackgroundPage(function(background) {
  ...
});

動作確認

無事Event Pageが閉じられると、以下のように (無効) と表示されます。タスク マネージャでもプロセスが存在していないことが確認できるはずです。

Event Pageが無効化された様子

参考

公式のドキュメントがとても親切でよいです。サンプルのGoogle Mail Checkerを見ればだいたい使い方はわかると思います。