русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Обработчики событий и утечки памяти


Дата добавления: 2015-07-09; просмотров: 470; Нарушение авторских прав


 

Как уже говорилось в пункте 8.8.4.2, Internet Explorer (вплоть до версии 6) стра_ дает утечками памяти, связанными с тем, что в качестве обработчиков событий используются вложенные функции. Рассмотрим следующий фрагмент:

 

// Добавить обработчик, проверяющий правильность заполнения формы

function addValidationHandler(form) {

form.attachEvent("onsubmit", function( ) { return validate(); });

}

 

Когда вызывается эта функция, она добавляет обработчик события в заданный элемент формы. Обработчик события определен как вложенная функция, и хотя сама функция не ссылается ни на один из элементов формы, ссылки на них ока_ зываются захваченными в ее области видимости, как часть замыкания. В ре_ зультате элемент формы ссылается на JavaScript_объект Function, а объект (че_ рез цепочку области видимости) – обратно, на элемент формы. Такого рода цик_ лические ссылки могут вызывать в IE утечки памяти.

 

Одно из решений этой проблемы заключается в том, чтобы старательно избегать вложенных функций при программировании для IE. Другое решение – тщатель_ но удалить все обработчики событий в ответ на событие onunload(). В примере, который приводится в следующем разделе, используется второй вариант.

 

Пример: модель обработки событий, совместимая с IE

 

В этом разделе основное внимание уделяется ряду несовместимостей между мо_ делями обработки событий в IE и в DOM Level 2. В примере 17.2 представлен мо_ дуль, который преодолевает многие из этих несовместимостей. В модуле опреде_ лены две функции, Handler.add() и Handler.remove(), которые добавляют и удаля_ ют обработчики событий для заданного элемента. На платформах, поддерживаю_ щих метод addEventListener(), эти функции являются тривиальными обертками вокруг стандартных методов. Однако в IE 5 и более поздних версиях эти методы определены так, что преодолевают следующие несовместимости:



 

• Обработчики событий вызываются как методы зарегистрировавшего их эле_ мента.

• Обработчикам событий для расширения возможностей передается смодели_ рованный объект события, соответствующий стандарту DOM.

• Повторные попытки регистрации обработчиков событий игнорируются.

• С целью предотвращения утечек памяти в IE при выгрузке документа отме_ няется регистрация всех обработчиков событий.

 

Чтобы обработчики событий вызывались с корректным значением ключевого слова this, а также для того, чтобы передавать им смоделированный объект со_ бытия, в примере 17.2 функции_обработчики должны быть обернуты в другие функции, корректно вызывающие обработчиков. Самая интересная часть в этом примере – это программный код, который отображает функцию_обработчик, пе_ редаваемую методу Handler.add(), на функцию_обертку, фактически регистри_ руемую методом attachEvent(). Такого рода отображение должно выполняться


 

17.3. Модель обработки событий Internet Explorer
   

 

так, чтобы метод Handler.remove() мог удалить правильную функцию_обертку при удалении обработчиков в ходе выгрузки документа.

 

Пример 17.2. Код обеспечения совместимости с моделью события IE

/*

* Handler.js __ Переносимые функции регистрации и отмены регистрации

 

*

* Этот модуль определяет функции регистрации и отмены регистрации

* обработчиков событий Handler.add() и Handler.remove(). Обе функции

 

* принимают три аргумента:

*

* element: DOM_элемент, документ или окно, куда добавляется

* или откуда удаляется обработчик события.

 

*

* eventType: строка, определяющая тип события, для обработки которого

 

* вызывается обработчик. Используются имена типов в соответствии

* со стандартом DOM, в которых отсутствует префикс "on".

 

* Примеры: "click", "load", "mouseover".

*

* handler: Функция, которая вызывается при возникновении указанного

* события в заданном элементе. Данная функция вызывается как метод

 

* элемента, в котором она зарегистрирована, и ключевое слово "this"

* будет ссылаться на этот элемент. Функции_обработчику в качестве

 

* аргумента передается объект события. Данный объект будет либо

* стандартным объектом Event, либо смоделированным объектом.

 

* В случае передачи смоделированного объекта он будет обладать

* следующими свойствами, совместимыми со стандартом DOM: type, target,

 

* currentTarget, relatedTarget, eventPhase, clientX, clientY, screenX,

* screenY, altKey, ctrlKey, shiftKey, charCode, stopPropagation()

 

* и preventDefault()

*

* Функции Handler.add() и Handler.remove() не имеют возвращаемых значений.

 

*

* Handler.add() игнорирует повторные попытки зарегистрировать один и тот

* же обработчик события для одного и того же типа события и элемента.

 

* Handler.remove() не выполняет никаких действий, если вызывается

* для удаления незарегистрированного обработчика.

*

* Примечания к реализации:

 

*

* В броузерах, поддерживающих стандартные функции регистрации

 

* addEventListener() и removeEventListener(), Handler.add()

* и Handler.remove() просто вызывают эти функции, передавая значение false

 

* в третьем аргументе (это означает, что обработчики событий никогда

* не будут зарегистрированы как перехватывающие обработчики событий).

*

* В версиях Internet Explorer, поддерживающих attachEvent(), функции

* Handler.add() и Handler.remove() используют методы attachEvent()

* и detachEvent(). Для вызова функций_обработчиков с корректным значением

 

* ключевого слова this используются замыкания.

* Поскольку в Internet Explorer замыкания могут приводить к утечкам памяти,

 

* Handler.add() автоматически регистрирует обработчик события onunload,

* в котором отменяется регистрация всех обработчиков при выгрузке страницы.


 

432 Глава 17. События и обработка событий

* Для хранения информации о зарегистрированных обработчиках функция

* Handler.add() создает в объекте Window свойство с именем _allHandlers,

 

* а во всех элементах, для которых регистрируются обработчики, создается

 

* свойство с именем _handlers.

*/

var Handler = {};

 

// В DOM_совместимых броузерах наши функции являются тривиальными

 

// обертками вокруг addEventListener() и removeEventListener(). if (document.addEventListener) {

 

Handler.add = function(element, eventType, handler) { element.addEventListener(eventType, handler, false);

 

};

 

Handler.remove = function(element, eventType, handler) { element.removeEventListener(eventType, handler, false);

 

};

}

 

// В IE 5 и более поздних версиях используются attachEvent() и detachEvent()

// с применением некоторых приемов, делающих их совместимыми

 

// с addEventListener и removeEventListener.

else if (document.attachEvent) {

Handler.add = function(element, eventType, handler) {

// Не допускать повторную регистрацию обработчика

 

// _find() _ частная вспомогательная функция определена далее. if (Handler._find(element, eventType, handler) != _1) return;

 

// Эта вложенная функция определяется для того, чтобы иметь

// возможность вызвать функцию как метод элемента.

 

// Эта же функция регистрируется вместо фактического обработчика событий. var wrappedHandler = function(e) {

 

if (!e) e = window.event;

 

// Создать искусственный объект события, отчасти

// совместимый со стандартом DOM.

var event = {      
_event: e, // Если потребуется настоящий объект события IE
type: e.type, // Тип события
target: e.srcElement, // Где возникло событие

 

currentTarget: element, // Где обрабатывается relatedTarget: e.fromElement?e.fromElement:e.toElement, eventPhase: (e.srcElement==element)?2:3,

 

// Координаты указателя мыши

 

clientX: e.clientX, clientY: e.clientY, screenX: e.screenX, screenY: e.screenY,

 

// Состояние клавиш

 

altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, charCode: e.keyCode,

 

// Функции управления событиями

 

stopPropagation: function(){this._event.cancelBubble = true;}, preventDefault: function() {this._event.returnValue = false;}

 

}


 

17.3. Модель обработки событий Internet Explorer
   

 

// Вызвать функцию_обработчик как метод элемента, передать

// искусственный объект события как единственный аргумент.

// Если функция Function.call() определена _ использовать ее,

// иначе применить маленький трюк

 

if (Function.prototype.call) handler.call(element, event);

else {

// Если функция Function.call отсутствует,

// симулировать ее вызов.

 

element._currentHandler = handler; element._currentHandler(event); element._currentHandler = null;

}

};

 

// Зарегистрировать вложенную функцию как обработчик события. element.attachEvent("on" + eventType, wrappedHandler);

 

// Теперь необходимо сохранить информацию о пользовательской

// функции_обработчике и вложенной функции, которая вызывает этот

// обработчик. Делается это для того, чтобы можно было

// отменить регистрацию обработчика методом remove()

// или автоматически при выгрузке страницы.

 

// Сохранить всю информацию об обработчике в объекте.

var h = {

 

element: element, eventType: eventType, handler: handler,

wrappedHandler: wrappedHandler

};

 

// Определить документ, частью которого является обработчик.

// Если элемент не имеет свойства "document" _ это не окно

// и не элемент документа, следовательно, это должен быть

// сам объект document.

var d = element.document || element;

 

// Теперь получить ссылку на объект window, связанный с этим документом. var w = d.parentWindow;

 

// Необходимо связать этот обработчик с окном,

// чтобы можно было удалить его при выгрузке окна.

var id = Handler._uid(); // Сгенерировать уникальное имя свойства

 

if (!w._allHandlers) w._allHandlers = {}; // Создать объект, если необходимо w._allHandlers[id] = h; // Сохранить обработчик в этом объекте

 

// И связать идентификатор информации об обработчике с этим элементом. if (!element._handlers) element._handlers = []; element._handlers.push(id);

 

// Если связанный с окном обработчик события onunload

 

// еще не зарегистрирован, зарегистрировать его.

 

if (!w._onunloadHandlerRegistered) { w._onunloadHandlerRegistered = true; w.attachEvent("onunload", Handler._removeAllHandlers);

}


 

434 Глава 17. События и обработка событий

};

 

Handler.remove = function(element, eventType, handler) {

 

// Отыскать заданный обработчик в массиве element._handlers[]. var i = Handler._find(element, eventType, handler);

 

if (i == _1) return; // Если нет зарегистрированных обработчиков,

// ничего не делать

 

// Получить ссылку на окно для данного элемента.

 

var d = element.document || element; var w = d.parentWindow;

 

// Отыскать уникальный идентификатор обработчика. var handlerId = element._handlers[i];

 

// И использовать его для поиска информации об обработчике. var h = w._allHandlers[handlerId];

 

// Используя эту информацию, отключить обработчик от элемента. element.detachEvent("on" + eventType, h.wrappedHandler);

 

// Удалить один элемент из массива element._handlers.

element._handlers.splice(i, 1);

 

// И удалить информацию об обработчике из объекта _allHandlers. delete w._allHandlers[handlerId];

};

 

// Вспомогательная функция поиска обработчика в массиве element._handlers

 

// Возвращает индекс в массиве или _1, если требуемый обработчик не найден Handler._find = function(element, eventType, handler) {

 

var handlers = element._handlers;

if (!handlers) return _1; // Если нет зарегистрированных обработчиков,

// ничего не делать

 

// Получить ссылку на окно для данного элемента var d = element.document || element;

 

var w = d.parentWindow;

 

// Обойти в цикле обработчики, связанные с этим элементом, отыскать

// обработчик с требуемыми типом и функцией. Обход идет в обратном порядке,

// потому что отмена регистрации обработчиков, скорее всего,

// будет выполняться в порядке, обратном их регистрации.

for(var i = handlers.length_1; i >= 0; i__) {

 

var handlerId = handlers[i]; // Получить идентификатор обработчика var h = w._allHandlers[handlerId]; // Получить информацию

 

// Если тип события и функция совпадают, значит, требуемый обработчик найден. if (h.eventType == eventType && h.handler == handler)

 

return i;

}

return _1; // Совпадений не найдено

};

 

Handler._removeAllHandlers = function() {

// Данная функция регистрируется как обработчик события onunload

// с помощью attachEvent. Это означает, что ключевое слово this

 

// ссылается на объект window, в котором возникло это событие. var w = this;

 

// Обойти все зарегистрированные обработчики

for(id in w._allHandlers) {


 

17.4. События мыши
   

 

// Получить информацию об обработчике по идентификатору var h = w._allHandlers[id];

 

// Использовать ее для отключения обработчика h.element.detachEvent("on" + h.eventType, h.wrappedHandler);

 

// Удалить информацию из объекта window

delete w._allHandlers[id];

}

}

 

// Частная вспомогательная функция для генерации уникальных

// идентификаторов обработчиков

Handler._counter = 0;

Handler._uid = function() { return "h" + Handler._counter++; };

}

 



<== предыдущая лекция | следующая лекция ==>
Метод attachEvent() и ключевое слово this | Преобразование координат указателя мыши


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.472 сек.