Asset.images медленный?Как выполнить функции, чтобы они не зависали в браузере? - PullRequest
0 голосов
/ 06 февраля 2012

Недавно я скачал замечательный плагин mootools для предоставления системы оценки результатов поиска на моем сайте: MooStarRating .

Он работает довольно хорошо, но его инициализация происходит очень медленноВот время выполнения, которое я зарегистрировал (для получения 50 результатов поиска).

======== starrating ========
init:     0.06ms   50
img:      5.40ms   50
str:      0.54ms   50
each:     3.04ms   50
inject:   0.86ms   50
end:      1.52ms   50
subtotal: 11.42ms  50
-----------------
total:    571.00ms

Вот функция initialize, к которой относятся эти журналы (только для справки):

initialize: function (options) {

    lstart("starrating");

    // Setup options
    this.setOptions(options);

    // Fix image folder
    if ((this.options.imageFolder.length != 0) && (this.options.imageFolder.substr(-1) != "/"))
        this.options.imageFolder += "/";

    // Hover image as full if none specified
    if (this.options.imageHover == null) this.options.imageHover = this.options.imageFull;

    lrec("init");

    // Preload images
    try {
        Asset.images([
        this.options.imageEmpty,
        this.options.imageFull,
        this.options.imageHover
    ]);
    } catch (e) { };

    lrec("img");

    // Build radio selector
    var formQuery = this.options.form;
    this.options.form = $(formQuery);
    if (!this.options.form) this.options.form = $$('form[name=' + formQuery + "]")[0];
    if (this.options.form) {
        var uniqueId = 'star_' + String.uniqueID();
        this.options.form.addClass(uniqueId);
        this.options.selector += 'form.' + uniqueId + ' ';
    }
    this.options.selector += 'input[type=radio][name=' + this.options.radios + "]";
    // Loop elements
    var i = 0;
    var me = this;
    var lastElement = null;
    var count = $$(this.options.selector).length;
    var width = this.options.width.toInt();
    var widthOdd = width;
    var height = this.options.height.toInt();
    if (this.options.half) {
        width = (width / 2).toInt();
        widthOdd = widthOdd - width;
    }

    lrec("str");

    $$(this.options.selector).each(function (item) {

        // Add item to radio list
        this.radios[i] = item;
        if (item.get('checked')) this.currentIndex = i;

        // If disabled, whole star rating control is disabled
        if (item.get('disabled')) this.options.disabled = true;

        // Hide and replace
        item.setStyle('display', 'none');
        this.stars[i] = new Element('a').addClass(this.options.linksClass);
        this.stars[i].store('ratingIndex', i);
        this.stars[i].setStyles({
            'background-image': 'url("' + this.options.imageEmpty + '")',
            'background-repeat': 'no-repeat',
            'display': 'inline-block',
            'width': ((this.options.half && (i % 2)) ? widthOdd : width),
            'height': height
        });
        if (this.options.half)
            this.stars[i].setStyle('background-position', ((i % 2) ? '-' + width + 'px 0' : '0 0'));
        this.stars[i].addEvents({
            'mouseenter': function () { me.starEnter(this.retrieve('ratingIndex')); },
            'mouseleave': function () { me.starLeave(); }
        });

        // Tip
        if (this.options.tip) {
            var title = this.options.tip;
            title = title.replace('[VALUE]', item.get('value'));
            title = title.replace('[COUNT]', count);
            if (this.options.tipTarget) this.stars[i].store('ratingTip', title);
            else this.stars[i].setProperty('title', title);
        }

        // Click event
        var that = this;
        this.stars[i].addEvent('click', function () {
            if (!that.options.disabled) {
                me.setCurrentIndex(this.retrieve('ratingIndex'));
                me.fireEvent('click', me.getValue());
            }
        });

        // Go on
        lastElement = item;
        i++;

    }, this);

    lrec("each");

    // Inject items
    $$(this.stars).each(function (star, index) {
        star.inject(lastElement, 'after');
        lastElement = star;
    }, this);

    lrec("inject");

    // Enable / disable
    if (this.options.disabled) this.disable(); else this.enable();

    // Fill stars
    this.fillStars();

    lrec("end");

    return this;
},

Итак, самая медленная часть функции такова:

    // Preload images
    try {
        Asset.images([
        this.options.imageEmpty,
        this.options.imageFull,
        this.options.imageHover
    ]);
    } catch (e) { };

Что странно.Что делает Asset.images?Сценарий блокирует, пока эти изображения не были загружены браузером?Есть ли способ предварительной загрузки изображений, который работает быстрее?

Как я могу заставить скрипты на моей странице выполняться быстрее?Для них большая проблема - выполнение 800 мс, но 200 мс все еще довольно плохо.На данный момент все мои результаты поиска появляются сразу.Можно ли сделать так, чтобы отдельные результаты поиска создавались отдельно, чтобы они не блокировали браузер при создании?Аналогично, возможно ли это сделать для отдельных компонентов результатов поиска, таких как плагин MooStarRating?

1 Ответ

1 голос
/ 06 февраля 2012

нет. Asset.images является неблокирующим, так как каждый из них загружается отдельно, и когда все сделано, отправляется единичное событие.

скорость загрузки будет зависеть от браузера, но она будет многопоточна с любой возможностью параллельной загрузки с одного и того же хоста.

https://github.com/mootools/mootools-more/blob/master/Source/Utilities/Assets.js#L115-129

немедленно возвращает коллекцию элементов с ОБЕЩАНИЕМ элементов, которые все еще могут загружаться. это нормально - вы можете использовать его для вставки файлов, прикрепления событий, классов и т. д. - вы просто не можете прочитать свойства изображения, такие как ширина, высота.

каждое отдельное изображение имеет свой собственный onload, который запускает onProgress, а когда все будет сделано, onComplete для лота - я бы посоветовал вам включить это, удалите блок try / catch и посмотрите, какое изображение является создавая задержку. Вам, конечно, не нужно ждать, пока что-нибудь из Asset.images вернется.

вы также, похоже, используете его как метод «кеширования», больше всего - поскольку вы НЕ сохраняете ссылку в экземпляр класса. Ваша «каждая» итерация, вероятно, может быть оптимизирована, поэтому она использует половину времени, если объекты и функции кэшируются, и поэтому являются ссылками. вероятно, больше, если вы можете использовать делегирование событий.

Чтобы ответить на ваши вопросы о том, чтобы не замораживать браузер из-за однопоточной природы javascript, вы откладываете код через setTimeout (или Function.delay в mootools) с таймером, установленным в 0 или 10 мс, из-за интерпретаций браузера. Вы также пишете функцию для выполнения обратного вызова, когда закончите, в котором вы можете передать результат функции, если таковой имеется (подумайте ajax!).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...