Заметки за август 2009 года :: Хранитель заметок

noteskeeper.ru

Персональный журнал для заметок Владимира Кузнецова

Заметки за август 2009 года

Событие окончания загрузки картинки

Чтобы отследить момент загрузки картинки одного обработчика события «load» бывает не достаточно. Если он будет прикреплен к картинке после того, как она уже была загружена, то событие больше не повторится и обработчик не будет вызван.

Поможет решить эту проблему вспомогательный плагин к jQuery.

;(function ($) {
    $.fn.bindImageLoad = function (callback) {
        function isImageLoaded(img) {
            // Во время события load IE и другие браузеры правильно
            // определяют состояние картинки через атрибут complete.
            // Исключение составляют Gecko-based браузеры.
            if (!img.complete) {
                return false;
            }
            // Тем не менее, у них есть два очень полезных свойства: naturalWidth и naturalHeight.
            // Они дают истинный размер изображения. Если какртинка еще не загрузилась,
            // то они должны быть равны нулю.
            if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
                return false;
            }
            // Картинка загружена.
            return true;
        }

        return this.each(function () {
            var ele = $(this);
            if (ele.is("img") && $.isFunction(callback)) {
                ele.one("load", callback);
                if (isImageLoaded(this)) {
                    ele.trigger("load");
                }
            }
        });
    };
})(jQuery);

Обновление: Работу плагина можно посмотреть в примере. Там используется немного модифицированная версия, которая формирует специальное событие.

Очереди в jQuery

Важным инструментом для контроля последовательности исполнения функций в асинхронной среде являются очереди. Об одной из реализаций я писал в заметке «Очередь: синхронное выполнение функций».

В jQuery тоже есть механизм, реализующий очередь — это функции queue и dequeue.

Каждая именованная очередь прикрепляется к DOM элементу, который и будет контекстом выполнения функций. К одному элементу может быть прикреплено сколько угодно очередей. Важно лишь, чтобы они имели различные имена.

Рассмотрим пример:

$("#result")
    .queue("test", function () {
        $(this)
            .append("<p>1st function</p>")
            .queue("test", function () {
                $(this)
                    .append("<p>4th function</p>")
                    .dequeue("test");
            })
            .dequeue("test");
    })
    .queue("test", function () {
        $(this)
            .append("<p>2nd function</p>")
            .dequeue("test");
    })
    .queue("test", function () {
        $(this)
            .append("<p>3rd function. " +
                    $(this).queue("test").length +
                    " function(s) in queue</p>")
            .queue("test", function () {
                $(this)
                    .append("<p>5th function</p>")
                    .dequeue("test");
            })
            .dequeue("test");
    })
    .dequeue("test");

В нем я к элементу прикрепляю очередь из 3-х функций, затем в процессе выполнения этих функций в очередь добавляются еще 2.

Результатом работы этого кода будет:

1st function
2nd function
3rd function. 1 function(s) in queue
4th function
5th function

В третьей по счету функции выводится количество оставшихся функций в очереди. На момент исполнения там остается только одна функция (4-ая по счету), но сразу после этого добавляется еще и 5-ая.

Каждая функция по своему завершению должна вызвать метод dequeue, чтобы передать управление следующей функции в очереди.