среда, 19 февраля 2014 г.

Страницы управляемые событиями (Event Pages)

Это разновидность фоновых (Background) страниц, которые не хранятся в памяти постоянно, а загружаются только когда возникают связанные с ними события. Есть еще фоновые страницы, которые хранятся в памяти постоянно (persistent). Хотя и те и другие “фоновые”, но обычно, если в документации речь идет про фоновые, то имеются ввиду постоянные.

Гугл рекомендует разработчикам переносить свои наработки на event-страницы, что как бы намекает, что в один прекрасный день останутся только они.

Манифест

{
"name": "My extension",
...
"background": {
"scripts": ["eventPage.js"],
"persistent": false
},

По умолчанию свойство persistent = true и фоновая страница является постоянной.


Жизненный цикл


Страница типа event загружается при необходимости и уничтожается когда она не нужна. Строго говоря – не обязательно. Если быть точным, браузер может освободить занимаемые ей ресурсы при необходимости. А может и не освобождать если таковой не возникло. Логика может быть достаточно изощренной, например учитывать как часто возникают события связанные со страницей, но нам она неизвестна. Страница загружается когда:



  • Приложение(или расширение) установлено, или обновилось на новую версию. При этом регистрируются обработчики событий
  • Возникло событие
  • Странице отправлено сообщение контентным скриптом или другим расширением
  • Другой элемент расширения, например всплывающее окно вызвало метод runtime.getBackgroundPage.

Будучи загруженной, страница остается в памяти пока она активна. Например, пока ожидает результатов вызовов API или сетевых запросов. Она также остается загруженной, пока активны видимые элементы расширения (всплывающие окна) или каналы сообщений. Заметьте – открытие всплывающего окна не обязательно приводит к загрузке event-страницы, но препятствует ее закрытию. Вы можете наблюдать как страница загружается и когда освобождается в диспетчере задач браузера. Кстати, заглянув туда первый раз вы охренеете, сколько памяти жрут казалось бы простые странички.


Если страница неактивна несколько секунд, возникает событие runtime.onSuspend. После этого у страницы есть еще несколько секунд, если за это время что-то успеет случится, возникает событие runtime.onSuspendCanceled.


Нам эти детали в общем-то не должны быть интересны


Регистрация событий


Когда страница загружается, она регистрирует обработчики событий вызовом addListener. Если она удалит их с помощью removeListener – страница будет выгружена из памяти. При каждой загрузке страницы обработчики событий регистрируются заново


Если нужно выполнить какую-то инициализацию при установке расширения, то для этого необходимо регистрировать обработчик события runtime.onInstalled.


Переход от использования постоянных страниц к event-страницам



  1. Добавляем свойство “persistent” :  false в манифесте

  2. Если вы используете window.setTimeout() или window.setInterval(), заменяем их на вызовы chrome.alarms API. Не забываем, что использование этого API требует разрешения alarms

  3. Аналогично, все прочие асинхронные вызовы должны заменяться на вызовы chrome API

  4. Вызовы extension.getBackgroundPage необходимо заменить на runtime.getBackgroundPage. Разница между ними в том, что второй является асинхронным – страницу ведь надо еще загрузить.

Советы



  • Регистрируйте все обработчики которые могут быть интересны вашему расширению. Страница загружается один раз, когда расширение устанавливается. Потом она будет загружена только при возникновении зарегистрированного события.

  • Если вам нужно провести какую-то инициализацию после установки расширения, то добавьте обработчик события runtime.onInstalled. Это подходящее место для того чтобы задать правила declarativeWebRequest, или создать контекстное меню.

  • Используйте storage API или IndexedDB, если вам нужно что-то хранить

  • Фильтруйте события

  • Ставьте обработчик на runtime.onSuspend, если хотите что-то почистить перед тем как страница будет выгружена из памяти (на мой взгляд – плохая идея). Но вместо этого гугл советует периодически сохранять данные, иначе, если расширение внезапно накроется медным тазом, не успев получить runtime.onSuspend, то ваши данные могут пропасть. А еще лучше – в принципе не храните важных данных в переменных скрипта.

  • Если вы обрабатываете сообщения, не оставляйте открытыми неиспользуемые порты. Это будет препятствовать звкрытию страницы

  • Если вы используете контекстное меню, не используйте параметр onclick, а передавайте строковый параметр id и анализируйте его в обработчике contextMenus.onClicked

  • Типичные ошибки


    • выполнение ненужной работы при каждой загрузке страницы (например контекстное меню можно создать один раз – при установке)

    • Повторная установка алармов при каждой загрузке – они сбрасываются и начинают считать с начала.

    • Забытые обработчики событий: некоторые события могут быть обработаны двояко – путем создания обработчика или путем передачи callback-функции. Второй способ для event-страницы череват проблемами.

1 комментарий:

  1. Доброго времени суток. Хочу написать простенькое расширение с двумя кнопками: "копировать" и "вставить". На одной странице с таблицы нужно скопировать данные с определенных ячеек, а на другой странице вставить эти данные в форму. Как я понял, этот скрипт должен быть в "бэкграунде" для того, чтобы хранить данные в переменных. Это я и сделал, только кнопки в попапе не реагируют на клики. Потом решил инжектить сам скрипт и кнопки в код этих страниц. Но в этом случае два скрипта работают независимо друг от друга. Подскажите, пожалуйста, куда копать и как это должно выглядеть.

    ОтветитьУдалить