Jump to content
  • 0

[jQuery] Мой мозг взорван! Порядок выполнения обработчиков событий.


Aroused
 Share

Question

Код :


// js start
console.log('js start');

var hash = {
'set' : function(val){ window.location.hash = val },
'log' : function(){ console.log('Hash log: '+ window.location.hash) },
'bind': function(){ $(window).bind('hashchange', this.log) }
};

// set
hash.set('hash0');
hash.set('hash1');
hash.set('hash2');
hash.set('hash3');

// bind
hash.bind();

// js end
console.log('js end');

Резултат :


js start
js end
Hash log: #hash3
Hash log: #hash3
Hash log: #hash3
Hash log: #hash3

1. Консолим запуск.

2. Меняем хэш 4 раза.

3. Вешаем обработчик.

4. Консолим завершение.

Какого черта тут происходит?

Почему обработчик вообще сработал? (Откуда ему знать что я сделал до его навешивания?)

Почему хэш в консоле последний? (Ведь ни каких замыканий тут нет!)

Javascript - это скриптовый язык или где? :blink:

http://jsfiddle.net/ghTP9/

Edited by Aroused
Link to comment
Share on other sites

11 answers to this question

Recommended Posts

  • 0

Полагаю, дело в асинхронности очереди событий в JS. К моменту навешивания обработчика события еще как бы «висят в очереди», а значение #hash уже окончательное. Оно и логируется для каждого события.

Если навесить обработчик по таймауту (даже с нулевой задержкой), странность исчезает.

  • Like 1
Link to comment
Share on other sites

  • 0
Если навесить обработчик по таймауту (даже с нулевой задержкой)

Нулевая задержка на самом деле не нулевая.

Почему обработчик вообще сработал?

Пока я вижу только неправильную работу события(?) обработчика события.

  • Like 2
Link to comment
Share on other sites

  • 0

если сделать вот так:


// js start
console.log('js start');
var hash = {
'set' : function(val){
window.location.hash = val;
console.log("set");
},
'log' : function(){
console.log('Hash log: '+ window.location.hash);
console.log("log");
},
'bind': function(){
$(window).bind('hashchange', this.log);
console.log("bind");
}
};
// set
hash.set('hash0');
hash.set('hash1');
hash.set('hash2');
hash.set('hash3');
// bind
hash.bind();
// js end
console.log('js end');

Получите вот такой вывод:


js start
set
set
set
set
bind
js end
Hash log: #hash3
log
Hash log: #hash3
log
Hash log: #hash3
log
Hash log: #hash3
log

Порядок вызова верен.Сначала вывод в консоль потом 4 смены хеша, потом вызов обработчика.

Вы навешиваете обработчик на событие hashchange и он вам выводит текущий хеш столько раз сколько раз он вообще менялся. Вот это странно. Полез капать.

Link to comment
Share on other sites

  • 0

Сейчас я попробую объяснить почему меня это так беспокоит.

Для нового сервиса была выбрана технология «hash-bang».

https://developers.g...ification?hl=ru

Не буду приводить код, просто поясню где возникают проблемы.

1. Загрузка страницы.

2. Запись пар ключ - значение (из хэша) в объект.

3. Проверка этих значений на допустимые (типа там "page", "lang", etc..).

4. Правим хэш в случае некорректного значения (установки по умолчанию).

5. Вешаем одноразовый обработчик "hashchange" (для запуска пунктов 2, 3, 4, 5 и 6 данного списка).

6. Запускаем функцию синхронной подгрузки контента.

В итоге исходя из принципа работы обработчика, пункты 2, 3, 4, 5, 6 выполняются дважды (2, 3, 4, 5, 6, 2, 3, 4, 5, 6).

При переходе по «hash-bang» ссылке, так же выполняются пункты 2, 3, 4, 5, 6 дважды.

Первый запуск этих пунктов выполняется при клике по ссылке,

а второй инициирует четвертый пункт из списка выше (чего не должно происходить, ведь обработчик $.one(), хотя с $.bind() + $.unbind() то же самое ).

Если ни кто не понял о чем я сейчас написал, просто объясните почему после


console.log('js end');

выполняется срабатывание обработчиков?

И как кроме "нулевого" таймаута (кода много, таймаут опасен) обойти эту проблему?

Edited by Aroused
Link to comment
Share on other sites

  • 0

Всё таки это видимо из-за очереди, вот тут тот же вопрос обсуждается примерно http://stackoverflow...nge-event-in-js и упоминается плагин для jquery https://github.com/c...hange/tree/v1.3

но и там без таймаута не обошлось.

Даже и незнаю может не использовать вообще это событие. А вешать к примеру на все нужные ссылки клик и сверять хеши при кликах. Другого пока варианта я не вижу. Тем более событие onhashchange не кроссбраузерное.

Edited by wwt
  • Like 1
Link to comment
Share on other sites

  • 0

Может действительно криво реализован механизм этого события в jQuery.

Что самое странное, вообще никакого дока для bind('hashchange') на оффициальном сайте jQuery нет.

И еще, я искал в самом jquery.js хоть какие-то методы с "hashchange", но их тоже нет! Непонятно как это работает (но понятно что как-то криво). :wacko:

Тем более событие onhashchange не кроссбраузерное.

В ie 8 обработчик $().bind('hashchange') работает вроде :blush:, может у jQuery там проверка какая. Типа:


var event = "onhashchange" in window || "hashchange" in window

... хотя нет, не нашел.

Edited by Aroused
Link to comment
Share on other sites

  • 0

Может действительно криво реализован механизм этого события в jQuery.

Что самое странное, вообще никакого дока для bind('hashchange') на оффициальном сайте jQuery нет.

И еще, я искал в самом jquery.js хоть какие-то методы с "hashchange", но их тоже нет! Непонятно как это работает (но понятно что как-то криво). :wacko:

Это событие браузера. И в jQuery оно отрабатывает стандартным способом. Я пробовал заменять bind() на addEventListener(...) тоже самое происходит и без jquery. Поглядите исходники плагина по ссылке в моем прошлом посте, он неплохо документирован и добавлена поддержка старых браузеров через эмуляцию события, возможно что-то проясните))

  • Like 1
Link to comment
Share on other sites

  • 0

Может действительно криво реализован механизм этого события в jQuery.

Что самое странное, вообще никакого дока для bind('hashchange') на оффициальном сайте jQuery нет.

И еще, я искал в самом jquery.js хоть какие-то методы с "hashchange", но их тоже нет! Непонятно как это работает (но понятно что как-то криво). :wacko:

Тем более событие onhashchange не кроссбраузерное.

В ie 8 обработчик $().bind('hashchange') работает вроде :blush:, может у jQuery там проверка какая. Типа:


var event = "onhashchange" in window || "hashchange" in window

... хотя нет, не нашел.

да как раз с версии 8 он уже и есть. https://developer.mozilla.org/en-US/docs/DOM/Mozilla_event_reference/hashchange там есть версии браузеров которые его поддерживают.

Link to comment
Share on other sites

  • 0
Может действительно криво реализован механизм этого события в jQuery.

я первым делом на это подумал и переписал на чистом js. Результат тот же.

Я пробовал заменять bind() на addEventListener(...) тоже самое происходит и без jquery

вторая ласточка :)

Я согласен с wwt. По возможности лучше избегать этого события. По крайней мере, пока оно работает криво.

Еще я проверял в других браузерах (по дефолту у меня хром), подумал мало ли что. В лисе аналогично. Может, это такая фича и в стандарте об этом написано? Кто знает )

Edited by nerv
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy