Сокращение использования процессора при манипуляциях с JQuery DOM - PullRequest
1 голос
/ 18 марта 2012

Могу ли я что-нибудь сделать с этим кодом, чтобы повысить его эффективность использования процессора (сейчас он занимает около 80 процентов моего процессора)?Я выучил javascript вчера, так что, возможно, я неопытный.Этот код контролирует переходы довольно большого массива плиток.При наведении курсора плитки переворачиваются и снова переворачиваются на mouseoff.Будет запущено несколько потоков одновременно, я не вижу способа обойти это.Я использую этот сценарий, потому что мне нужно точно контролировать, что делают переходы способами, которые webkit-переходы не поддерживают.Надеемся, что комментарии являются достаточно значимыми, чтобы пролить свет на код.Функция активна, потому что массив плиток создается в javascript при загрузке страницы.После этого плитки больше не создаются.

Источник можно найти здесь.У меня еще нет рабочей загрузки.wikisend.com/download/811662/test.zip

Спасибо.

    //By default, javascript will not complete a hover transition unless the mouse 
remains over the entire duration of the transition. This scrip will force the hover 
transition to completion.
$(document).ready(function() {
    $('.tile').live('mouseenter mouseleave', (function() {

    if (event.type == 'mouseover') {
        var $this = $(this);
        $this.addClass('hover');

        //prevents mouseleave from happening when user re-enters after exiting before time is up
        $this.data('box-hover-hovered', false);
        //tile is not ready for leaving hover state
        $this.data('box-hover-not-ready', true);
        var timeout = setTimeout(function() {
            //box will be ready after time is up
            var state = $this.data('box-hover-hovered');
            if (state) { //this is entered when user exits before
                //time is up
                $this.removeClass('hover');
            }
            $this.data('box-hover-not-ready', false);
            //it's ready
        }, 400); // .1 second
        // Remove previous timeout if it exists
        clearTimeout($this.data('box-hover-timeout'));
        //stores current timer id (current timer hasn't executed yet)
        $this.data('box-hover-timeout', timeout);
    }

    else {
        var $this = $(this);

        // If not not-ready, do nothing
        // By default, the value is `undefined`, !undefined === true
        var not_ready = $this.data('box-hover-not-ready');
        if (!not_ready) {
            //if user remains hovering until time is up.
            $this.removeClass('hover');
        } else {
            //user would not have completed the action
            $this.data('box-hover-hovered', true);
        }
    }
}));
});​

Ответы [ 2 ]

3 голосов
/ 18 марта 2012

ОК, если вы хотите убедиться, что переход без зависания к транзиту завершен до того, как вы переключитесь, вы можете сделать это следующим образом:

$(document).ready(function() {
    $(document.body).on('mouseenter mouseleave', '.tile', function(event) {
        var $this = $(this);
        if (event.type == 'mouseenter') {
            $this.data("hovering", true);
            if (!$this.hasClass('hover')) {
                $this.addClass('hover');
                var timeout = setTimeout(function() {
                    $this.removeData("timer");
                    if (!$this.data("hovering")) {
                        $this.removeClass('hover');
                    }
                }, 400);
                $this.data("timer", timeout);
            }
        } else {
            $this.data("hovering", false);
            // if no timer running, then just remove the class now
            // if a timer is running, then the timer firing will clear the hover
            if (!$this.data("timer")) {
                $this.removeClass('hover');
            }
        }
    });
});​

И вот рабочая демонстрация с полнымКомментарии к коду: http://jsfiddle.net/jfriend00/rhVcp/

Это довольно подробное объяснение того, как это работает:

  • Во-первых, я переключился на .on(), поскольку .live() устарел для всех версийjQuery.Вам следует заменить document.body ближайшим предком статического объекта .tile.
  • Объект содержит элемент .data("hovering", true/false), который всегда сообщает нам, находится ли мышь над объектом или нет, независимо от.hover состояние класса.Это необходимо, когда срабатывает таймер, поэтому мы знаем, какое истинное состояние необходимо установить в этой точке.
  • Когда происходит событие mouseenter, мы проверяем, существует ли класс hover.,Если так, то делать нечего.Если класс hover отсутствует, мы добавляем его.Так как он ранее не присутствовал, и мы просто добавили его, это будет началом перехода hover.
  • Мы устанавливаем таймер для длины перехода и устанавливаем элемент .data("timer", timeout) для объекта, чтобы будущий код мог знать, что таймер уже запущен.
  • Если мы получим mouseleave до того, как этот таймер сработает, мы увидим, что .data("timer") существует, и мы ничего не будем делать (что позволит завершить переход).
  • Когда таймер сработает, мы делаем .removeData("timer"), чтобы избавиться отэтот маркер и затем мы видим, что мы все еще зависаем или нет с .data("hovering").Если мы больше не зависаем (поскольку mouseleave произошло во время работы таймера), мы делаем .removeClass("hover"), чтобы перевести объект в нужное состояние.Если мы все еще зависли, мы ничего не делаем, потому что мы все еще зависли, поэтому объект уже находится в правильном состоянии.

В двух словах, когда мы запускаем зависание, мы устанавливаем наведениесостояние и запустить таймер.Пока этот таймер работает, мы не меняем состояние объекта.Когда таймер срабатывает, мы устанавливаем правильное состояние объекта (зависание или отсутствие зависания, в зависимости от того, где находится мышь).Это гарантирует, что состояние при наведении останется включенным, по крайней мере, на время перехода, и когда пройдет минимальное время (таким образом, переход выполнен), мы обновим состояние объекта.

очень осторожно, не используйте глобальные переменные, так что это может работать с несколькими .tile объектами без какого-либо вмешательства между ними.

В важной точке проектирования вы никогда не сможете запустить более одного таймера, потому что таймер только когда-либоустанавливается, когда класс hover не существует, и мы просто добавляем его сейчас, и когда таймер работает, мы никогда не удаляем класс hover, пока таймер не будет завершен.Таким образом, нет пути к коду для установки другого таймера после его запуска.Это упрощает логику.Это также означает, что таймер запускается только с момента первого применения класса hover, что гарантирует, что мы применяем время только с классом hover с момента его первого применения.

Что касается производительности, переход CSSЯ собираюсь использовать любой процессор - это зависит от реализации браузера, и мы ничего не можем с этим поделать.Все, что мы можем сделать, чтобы минимизировать нагрузку на процессор, это убедиться, что мы делаем минимально возможное при каждом переходе мыши / выходе и избегаем манипуляций с DOM, когда это возможно, поскольку они обычно являются самыми медленными типами операций.Здесь мы добавляем класс hover только тогда, когда он еще не существует, и удаляем его только тогда, когда время истекло, и мышь больше не находится над ним.Все остальное - просто .data() операций, которые являются просто манипуляциями с хеш-таблицами javascript, которые должны выполняться довольно быстро.Это должно инициировать перекомпоновку браузера только в случае необходимости, что является лучшим, что мы можем сделать.

Производительность селектора здесь не должна быть проблемой.Это делегированная обработка событий, и единственный селектор, который проверяется в реальном времени (во время событий), это .tile, и это очень простая проверка (просто проверьте, есть ли у event.target этот класс - никаких других объектов не нужноОдна вещь, которая была бы важна для производительности, - это выбрать предка как можно ближе к '.tile' для делегированной привязки события, потому что это будет тратить меньше времени на создание события, прежде чем оно будет обработано, и вы не получите условиегде существует множество делегированных событий, связанных с одним и тем же объектом, что может быть медленным, и поэтому .live() устарело.

1 голос
/ 18 марта 2012

Edit: см. Комментарий dbaupp ниже.

Сразу скажу, использовать более специфичный селектор вместо просто $ ('. Tile'). Это просто означает, что вместо этого нужно изменить ваш селектор на что-то вроде $ ('div.tile') или еще лучше $ ('# someparentid div.tile').

Таким образом, вам не придется обходить весь DOM в поисках подходящего класса.

Боюсь, Микко, похоже, совершенно прав http://jsperf.com/jquery-right-to-left-selectors

Очевидно, мое решение было старым заблуждением. Хорошие способы улучшить производительность селектора jQuery?

Единственный способ ускорить этот селектор - это вызвать его по id (например, $ ('# tile')), что, к сожалению, не похоже на решение, которое будет работать для вас, учитывая, что вы, вероятно, имеете несколько плиток элементы.

...