2014-12-05 2 views
1

나는 상대적으로 위치가 정해진 요소를 현재 위치에서 1000px 벗어나 슬라이드하는 다음과 같은 기능을 가지고 있습니다.JavaScript 함수 및 UI 업데이트

for (var i = 0; i < 1000; i++) { 
    $('.my-element').css(
     'left', 
     parseInt($('.my-element').css('left'), 10) + 1 
    ); 
} 

이것은 슬라이딩 효과를 생성하지 않습니다. 오히려 실행이 끝날 때까지 요소는 갑자기 1000px 오른쪽으로 이동합니다.

이제 I는 다음과 같이의 setTimeout에서 UI 업데이트를 감싸는 경우 :

for (var i = 0; i < 1000; i++) { 
    setTimeout(function() { 
     $('.my-element').css(
      'left', 
      parseInt($('.my-element').css('left'), 10) + 1 
     ); 
    }, 0); 
} 

이 그 오른쪽 1000px 슬라이딩 요소의 시각적 효과를 생성한다.

내 스레드 및이 SO 스레드 Why is setTimeout(fn, 0) sometimes useful?에 따르면 UI 업데이트는 setTimeout 콜백처럼 대기중인 async 콜백과 동일한 방식으로 브라우저 이벤트 큐에 대기합니다.

그래서 기본적으로 for 루프가 실행될 때 기본적으로 1000 개의 UI 업데이트 대기열이 만들어집니다.

그리고 두 번째로 먼저 1000 개의 setTimeout 콜백 큐가 생성됩니다.이 큐는 실행시 1000 개의 UI 업데이트 큐를 새로 만듭니다.

결국 결국 두 경우 모두 1000 개의 UI 업데이트 대기열을 만듭니다. 그렇다면 시각적 인 결과의 차이점은 무엇입니까?

여기서는 중요한 JavaScipt 및 브라우저 렌더링 개념을 살펴보아야합니다. 나를 계몽 할 수있는 사람은 누구나 감사 할 것입니다.

참고 : 위 예제는 전적으로 목적을 이해하는 데 사용되며 DOM 요소를 슬라이드하기위한 JS 함수를 만들려는 시도가 아닙니다.

+1

로건은 확실히 당신의 질문에 대한 대답,하지만 난 루프 대신 슬라이딩 효과를 수행하기 위해 [jQuery.animate] (http://api.jquery.com/animate/)에보고 제안했다. 그냥 for 루프의 모든 반복은 DOM을 가로 지르며'.my-element'의 클래스를 가진 모든 엘리먼트를 찾는다 고 생각합니다 - 거의 효율적이지 않습니다! – chazsolo

+0

이 예제는 브라우저가 JavaScript를 실행하고 UI를 업데이트하는 방법을 이해하기위한 것입니다. 슬라이딩 기능을 만들려는 시도가 아닙니다. – Prashant

답변

5

아마도 이것은 생각하는 가장 좋은 방법 일 것입니다. 브라우저는 두 가지 중 하나를 수행 할 수 있습니다. 그것은 자바 스크립트를 실행하거나 webapge를 렌더링합니다. 둘 다 수행 할 수는 없습니다.

자바 스크립트 코드가 100 % 차단되어 있기 때문에 브라우저가 모든 차단 코드를 실행할 때까지 제어를 포기하지 않습니다.

첫 번째 예제에는 차단 코드 만 포함되어 있기 때문에 요소가 이미 있어야 할 때까지 브라우저에 렌더링 기회가 제공되지 않습니다.

두 번째 예제에는 브라우저 재량에 따라 (다른 모든 차단 코드가 완료된 후) 나중에 실행될 차단 코드 묶음을 대기열에 넣는 setTimeout (지연된 차단 코드)을 사용하는 차단 코드가 포함되어 있습니다 (실행 및 자바 스크립트 실행주기).

두 번째 예제에서는 루프가 완전히 실행되어 1000 개의 큐를 실행하여 특정 시점에서 실행될 수 있지만 가능한 한 0ms에 가깝게 실행합니다. 이제 블로킹 코드가 완료되어 하나 이상의 setTimeout이 실행되거나 브라우저가 실제로 랜덤하게 렌더링됩니다. 그러나 그것은 렌더링과 자바 스크립트 실행 사이를왔다 갔다합니다.

예를 들면 다음과 같습니다.

setTimeout(function() { //this makes it so the page loads and sits for a second 
    var delay = 100, //delay between animations 
     distance = 25, //total distance moved 
     sync = false; //should this use blocking code 

    if (sync) { 
     var i = 0, 
      elapsed = 0, 
      last = new Date(); 
     while (i < distance) { 
      var now = new Date(); 
      elapsed += (now - last); 
      last = now; 
      if (elapsed >= delay) { 
       move(i++); 
       elapsed -= delay; 
      } 
     } 
    } else { 
     for (var i = 0; i < distance; i++) { 
      assyncMove(i, delay * i); 
     } 
    } 

    function assyncMove(position, delay) { 
     setTimeout(function() { 
      move(position); 
     }, delay); 
    } 

    function move(position) { 
     $("div").css("left", position); 
    } 
}, 1000); 

당신은 delay, distancesync 변수를 변경할 수 있습니다. 두 루프는 각 애니메이션 사이에 요소 delay 밀리 초를 이동하기 위해 대기합니다. 그들은 모두 distance 픽셀의 div를 움직일 것입니다.그러나 하나 (setTimeout)는 보이는 애니메이션을 가지지 만 다른 애니메이션은 그냥 넘어갑니다. 동기화 방법으로 지연 또는 거리를 너무 길게 만들면 실제로 브라우저가 고정되므로 assync 솔루션에는 문제가 없습니다!

http://jsfiddle.net/j79s4o4w/3/

+0

그러나 UI 업데이트가 브라우저 이벤트 큐에 대기중인 경우 첫 번째 예제는 브라우저가 각 큐 항목의 다른 위치에 요소를 칠해야하는 UI 업데이트를 큐에 추가합니다. (따라서 시각적 효과가 미끄러진다.) 두 번째 예제에서 1000 개의 대기열에있는 setTimeout 콜백은 setTimeout 콜백 끝에 1000 개의 UI 업데이트를 만들어야하는데, 이는 나에게 첫 번째 예제와 동일하다. – Prashant

+0

@PrashantPalikhe 첫 번째 예제에는 대기열이 없습니다. 스크립트는 요소의 왼쪽 CSS 속성을 1000 번 변경합니다. 브라우저가 페이지를 렌더링하면 최종 결과 만 보입니다. CSS 속성을 변경해도 그 자체로 다시 그리기가 실행되지는 않습니다. – JJJ

+0

http://stackoverflow.com/a/4575011/694877 좋습니다, 즉 연결된 스레드에 대한이 주석은 오해의 소지가 있음을 의미합니다. setTimeout이없는 그의 예에서 그는 큐에 추가되는 UI 업데이트에 대해 언급합니다. JS 함수가 끝날 때까지 엘리먼트를 다시 그리는 속도가 빨라서 세 가지 다른 UI 업데이트가 발생하더라도 마지막 UI 만 표시되는 것처럼 보입니다. – Prashant