2013-10-09 2 views
6

mousemove에 연결된 jQuery 이벤트 전달 성능에 문제가 있습니다.jQuery mousemove 성능 - 스로틀 이벤트?

화면 채우기 캔버스가 있고 사용자가 마우스를 드래그하면 추적해야하므로 해당 객체에 마우스 이동 수신기가 추가되었습니다. 같은 :

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

이 코드는 잘 작동하지만, 우리는 하나의 테스트 시스템의 현재 파이어 폭스 (24)에 심각한 성능 문제가 있었다. 프로파일 러는 대부분의 시간이 jQuery.event.dispatch() (우리는 현재 최신 jQuery 1.8, 1.9, 1.10 및 2.0을 시도했습니다)에서 소비되었다고 알려줍니다.

여기서 "jQuery.event.fix()"성능 최적화를 사용하여 dispatch() 함수에 소요 된 시간을 줄였습니다 : http://bitovi.com/blog/2012/04/faster-jquery-event-fix.html 그러나 테스트 시스템의 성능은 여전히 ​​예상보다 낮았습니다.

몇 가지 추가 테스트 후, 나는 시스템에 사용되는 마우스에이를 핀 관리 : 그것은 를 1000Hz을 사용했다. 사용 된 마우스를 125Hz로 바꿨고 성능이 좋았습니다.

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 
     } 
    } 
}); 
:

우리의 가정이었다

, 마우스의 높은 Hz의 속도에서 mousemove 이벤트가 많이 발생하는 것으로, 그래서 우리는 이벤트 스로틀을 적용하고 매 X 밀리 초 이벤트 처리를 호출하는 위의 코드를 변경

그리고 그것은 charme처럼 작동했습니다, 성능이 좋았습니다. 2 밀리 초의 이벤트 만 건너 뛸 수 있습니다.

지금 나는 두 가지 질문이 있습니다

  1. 우리는 우리가 내가 그 mousemove 핸들러 모든이 손으로 만든 스로틀을 추가 할 다른 HTML 요소에 MouseMove 이벤트 리스너를 부착하고 다른 위치가 문제가 다시 발생하지 않도록해야합니다. 이것이 어떻게 든 jQuery (2.0.3)에서 좋은 방법으로 할 수 있습니까? 나는 preDispatch jQuery 자바 스크립트에서 후크를 본 적이 있지만 그들은 이미 또한 시간을 사용하는 fix()에 대한 호출이 끝난 후에도 호출을 저장하고 싶습니다.

  2. 얼마나 많은 이벤트가 건너 뛰고 있는지보기 위해 카운터를 추가 했으므로, 실제로는 2 분의 1 초당 eventThrottle이면 충분하다는 사실에 당혹 스러웠습니다. 놀라운 결과 : 0-1 이벤트 만 건너 뜁니다. 스로틀이 100ms 인 경우 스킵 된 이벤트는 60-70 정도 였으므로 ms 당 1mousemove 이벤트 미만인 경우이 코드에 어쨌든 그런 긍정적 인 효과? 당신이 in the examples을 읽을 수 있듯이 https://github.com/cowboy/jquery-throttle-debounce

    , 당신은 대체 할 수있다 :

    // 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

1 스로틀 jQuery 플러그인이 2 - 처리기의 코드를 게시 하시겠습니까?

하나의 눈먼 제안 : Firebug는 FF24에서 성능 문제가 있습니다. 성능을 Firebug 사용/사용 안함과 비교해 보았습니까?

+0

고맙습니다 : @ 1 :'setTimeout()'과'clearTimeout()'을 사용하는 재미있는 플러그인이지만 실제 이벤트 처리를 제한하지는 않습니다. 두 가지 부작용 : 1 : 나는 여전히'$ .on()'대신에'.throttle()'을 호출해야한다. (여러개의 개발자에게는 어렵다). 2 : CPU 무거운 jQuery 프로세싱 오버 헤드가 여전히 존재합니다 ('fix()'호출 ...). 어쩌면 가장 깨끗한 해결책은 jQuery 이벤트 처리 함수를 "플러그인"으로 덮어 쓰는 것입니다[email protected] 2 우리의 핸들러는'requestAnimationFrame'에서 돌아가는 루프에서 접근 한 몇몇 변수를 변경합니다. @Firebug : 당신은 Firebug가 비활성화 된 상태로 측정 된 FF24 정도입니다. –

+0

CPU를 먹는 것에 도움이 필요하면 코드를 게시해야합니다 ... – LeGEC

3

2015 년 말에 나는 결국이 문제가 무엇인지 발견했다.

내 브라우저 앱에서 특정 위치에 다양한 크기의 여러 원을 칠한 다음 전체 화면의 보이는 부분을 드래그하여 현재 확대/축소 수준에서 볼 수있는 전체 배경의 원만 표시합니다. 마우스를 드래그하면 mousemove 이벤트가 생성되어 내 렌더링 루틴 호출이 트리거되고 각 루틴이 다시 표시됩니다.

IE 11에서 이것을 테스트 한 결과, 볼 수있는 영역에 약 100 개 이상의 원이 있으면 마우스를 드래그하는 동안 렌더링이 매우 고르지가된다는 것을 발견했습니다. 프로파일 러는 이것이 거의 paint() 루틴 때문이라고 지적했습니다.

내 코드가 이미 라이브러리에서 requestAnimationFrame()을 사용하고있었습니다. 흥미롭게도 화면을 드래그하는 동안 느려지는 것을 보았습니다. 그러나 화면을 드래그하고 놓은 경우 라이브러리 코드가 계속해서 감속으로 움직임을 움직이게하고 다시 칠하는 것은 버터처럼 부드럽게 진행됩니다. 둔화는 마우스를 끌 때만 발생했습니다. 문제는 확실히 mousemove와 같았습니다. (잠시 후 이것으로 돌아 오십시오.)

나는 paint() 루틴을 단순한 채워진 원호 - 비슷한 문제로 깎아 냈다. 나는 확대/축소 레벨을 변경할 때마다 채워진 원을 화면 밖 캔버스에 칠해 보았습니다. 그런 다음 drawImage()를 사용하여 오프 스크린 캔버스를 기본 화면으로 복사했습니다.이 향상된 성능 이었지만 여전히 IE에서는 고르지 못하게 고르지 않았습니다. 그런 다음이 기술을 사용하여 모든 원을 오프 스크린 캔버스로 페인트하여 기본 표시 윈도우와 동일한 크기로 변경 한 다음 페인트()를 변경하여 오프 스크린 캔버스를 복사하여 캔버스에 복사합니다. 그러나 충분하지 않습니다.

나는 다음 다양한 브라우저에서 내 응용 프로그램을 실행하려고 :

IE 11 : 매우 고르지 파이어 폭스 42 : 매우 고르지 크롬 47 : 모든 줌 레벨 에서 완벽하게 매끄러운 : 모든 줌 레벨 오페라 34에서 완벽하게 매끄러운 데스크톱 사파리 5.1.7 (PC) : 모든 줌 레벨에서 약간 고르지

이 문제는 확실히 mousemove 및 다른 브라우저에서 어떻게 처리되는지와 관련이 있습니다.

결국이 질문은 StackOverflow와 마우스 자체가 너무 많은 mousemove 이벤트를 보내서 브라우저의 기능을 충분히 빠르게 다시 채우고 있음을 알게되었습니다. 그리고 나는 높은 이벤트 발생률을 가진 현대 마우스를 가지고있다.

mousemove 이벤트 처리기에 eventThrottle 검사를 추가하려고 시도했습니다. 성공. 이제 내 코드가 모든 브라우저에서 부드럽게 렌더링됩니다. (즐거움과 함께 Upvoted. :)

고주파 마우스로 드래그하는 동안 IE 및 Firefox에서 불량 paint() 성능 문제가 발생할 수있는 사람을 위해이 추가 정보를 추가하고 싶습니다. mousemove 이벤트를 조절하는 제안 된 솔루션이 나를 위해 일했습니다.