2013-10-09 1 views
6

Мы столкнулись с проблемой, с JQuery производительность распространения событий, связанных с MouseMove:jQuery mousemove performance - дроссельные события?

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

ourCanvas.on('mousemove', 
    function(event) { 
     event.preventDefault(); 
     //our drag code here 
    } 
}); 

Этот код работает отлично, но у нас были серьезные проблемы с производительностью в текущем Firefox (24) на одной тестовой системе. Профилировщик говорит нам, что большую часть времени проводилось в jQuery.event.dispatch() (мы опробовали последние jQuery 1.8, 1.9, 1.10 и 2.0).

Мы успешно сократили время, затрачиваемое на функцию dispatch(), используя оптимизацию производительности jQuery.event.fix(): http://bitovi.com/blog/2012/04/faster-jquery-event-fix.html, но производительность в этой тестовой системе все еще была ниже ожидаемой.

После некоторого дальнейшего тестирования, мне удалось прикрепить это вниз на мыши, используемой в системе: Она используется 1000Hz. Мы переключили используемую мышь на 125 Гц и вуаля, производительность была отличная.

Наше предположение было, что высокая частота Гц на мыши вызвало много MouseMove событий, поэтому мы изменили код выше, чтобы применить дроссель события и вызывать только обработку событий каждые X миллисекунд:

var lastMove = 0; 
var eventThrottle = 1; 
ourCanvas.on('mousemove', 
    function(event) { 
     event.preventDefault(); 
     var now = Date.now(); 
     if (now > lastMove + eventThrottle) { 
      lastMove = now; 
      //our drag code here 
     } 
    } 
}); 

И это работало как шарм, исполнение было замечательным. Хотя мы пропускаем только две миллисекунды событий.

Теперь у меня есть два вопроса:

  1. У нас есть другие места, где мы крепим MouseMove слушателей различных HTML-элементы и Я хотел бы добавить ручной дроссель все эти mousemove обработчиков чтобы снова не столкнуться с проблемой. Возможно ли это как-то сделать в jQuery (2.0.3)? Я видел preDispatch крючки в jQuery javascript, но они уже после вызова fix(), который также использует некоторое время, и я также хотел бы сохранить этот вызов.

  2. Я был озадачен тем фактом, что уже достаточно было eventThrottle 2ms, чтобы получить действительно хорошую производительность, поэтому я добавил счетчик, чтобы узнать, сколько событий пропущено. Удивительный результат: он пропускает только события 0-1 ... С дроссельной заслонкой 100 мс пропущенные события были в порядке 60-70, поэтому , если есть менее 1 события mousemove за мс, почему этот код имеет такой положительный эффект в конце концов?

Спасибо за любые комментарии, Кристофер

ответ

2

1 - есть дроссель JQuery плагин: https://github.com/cowboy/jquery-throttle-debounce

Как вы можете прочитать in the examples, вы можете заменить:

// Bind the not-at-all throttled handler to the resize event. 
$(window).resize(handler); 

// Bind the throttled handler to the resize event. 
$(window).resize($.throttle(250, handler)); // This is the line you want! 

2 - Вы хотите опубликовать код своего обработчика?

Ослепительное предложение: Firebug имеет проблемы с производительностью с FF 24. Пробовали ли вы сравнивать показатели с включенным/отключенным Firebug?

+0

Спасибо: @ 1: Интересный плагин с использованием 'setTimeout()' и 'clearTimeout()', но он не ограничивает обработку фактических событий. Два побочных эффекта: 1: мне все равно нужно называть '$ .throttle()' вместо '$ .on()' (трудно достичь с несколькими разработчиками). 2: Накладные расходы процессора jQuery по-прежнему остаются (вызовы 'fix()', ...). Возможно, самым чистым решением было бы перезаписать функцию обработки jQuery как «плагин»[email protected] 2 Наш обработчик изменяет некоторые переменные, получаемые из цикла, запущенного на 'requestAnimationFrame'. @Firebug: Вы правы в FF24, только измеряется с отключенным Firebug. –

+0

Если вы хотите получить помощь по тому, что съедает ваш процессор, вам придется опубликовать код ... – LeGEC

3

В конце 2015 года я столкнулся с тем, что я в конце концов обнаружил, была эта проблема.

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

При тестировании этого в IE 11 я обнаружил, что, когда у меня было около 100 кругов в видимой области, рендеринг при перетаскивании мыши стал чрезвычайно изменчивым. Профилер указал, что это было почти полностью из-за процедуры paint().

Мой код уже использует requestAnimationFrame() в библиотеке. Интересно, что, перетаскивая экран, я видел замедление; но если бы я только перетащил экран и выпустил его, позволяя библиотечному коду продолжать оживлять движение с замедлением, перекраска была бы гладкой, как масло. Замедление произошло только при перетаскивании мыши. Проблема, определенно, казалась с mousemove. (Обратно к этому в одно мгновение.)

Я уменьшил рутину() до ничего, кроме простой заполненной дуги - той же проблемы. Я попытался покрасить заполненный круг на экранное полотно всякий раз, когда я изменил уровень масштабирования, а затем с помощью drawImage(), чтобы скопировать экранный холст на мой основной экран - это улучшило производительность, но в IE оно все еще было нестабильным. Затем я попытался использовать эту технику, чтобы нарисовать все круги на заставном холсте того же размера, что и мое главное видимое окно, а затем сменить paint(), чтобы ничего не делать, кроме как скопировать заставку на мой видимый холст - это снова дало небольшое улучшение, но недостаточно.

Затем я попытался запустить мое приложение в различных браузерах:

IE 11: очень изменчивый Firefox 42: очень изменчивый Chrome 47: идеально гладкий на всех уровнях масштабирования Opera 34: идеально ровных на всех уровнях масштабирования Desktop Safari 5.1.7 (на ПК): слегка измененный на всех уровнях масштабирования

Проблема была определенно связана с mousemove и с тем, как она обрабатывается различными браузерами.

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

Я попробовал добавить eventThrottle check к моему обработчику событий mousemove и voila! Успех. Теперь мой код плавно отображается во всех браузерах. (Упрощенный с удовольствием :))

Я хотел добавить эту дополнительную информацию для тех, кто может столкнуться с проблемой плохой работы paint() в IE и Firefox при перетаскивании с помощью высокочастотной мыши. Предлагаемое решение для дросселирования муссовых событий сработало для меня.

 Смежные вопросы

  • Нет связанных вопросов^_^