2016-07-07 2 views
1

내가 개발해온 응용 프로그램의 UI에서 특정 (동기식) 처리가 시작되고 처리가 끝난 후에 숨기기 전에 "로더"div를 표시하려고했습니다. 그러나 전체 처리 중에는 로더가 전혀 나타나지 않습니다.Javascript가 실행되는 동안 브라우저의 리플 로우가 트리거되지 않는 이유는 무엇입니까?

가능한 경우 브라우저는 불필요한 리플 로우를 제거하여 렌더링 프로세스를 최적화하려고합니다. 리플 로우 프로세스를 수동으로 실행할 수있는 몇 가지 방법이 있지만 (예 : 광산과 같은 경우), 그 중 일부는 작동시키지 못했습니다. 다음은 offsetHeight의 계산이 리플 로우를 유발하는 데 사용되지만 TEST div가 전혀 나타나지 않는 최소한의 예제입니다. 요소

  • 창의

    • 는 offsetHeight의 계산 :

      <html> 
      <head> 
      <script src="https://code.jquery.com/jquery-2.2.4.js"></script> 
      </head> 
      <body> 
      <div id="test" style="display:none; background-color:red; height:500px">TEST</div> 
      
      <script> 
          function reflow() { 
           var t = $("#test")[0].offsetHeight; 
           $(window).trigger('resize'); 
           window.getComputedStyle($("#test")[0], null); 
           $("#test").focus(); 
          } 
      
          $("#test").show(); 
          reflow(); 
          console.log("Processing started"); 
          var sum = 0; 
          for(i = 0; i < 100000000; i++) { 
           sum += i; 
          } 
          console.log("Processing ended"); 
          $("#test").hide(); 
      <script> 
      </body> 
      </html> 
      

      작업 JSFiddle도

      있는 몇 가지 방법 here은 (스크립트에서 볼 수 있듯이) 다음과 같다 리플 로우를 강제로 시도 크기 조정

    • window.getComputedStyle()
    • 요소의 초점

    참고 : 시간 초과를 추가하여 해결할 수 있습니다. 그러나 타임 아웃은 "해킹"이므로이 기능에 적합하지 않기 때문에 리플 로우를 강제하는 방법을 찾고 싶습니다.

  • +1

    js가 단일 스레드 언어 이상인 문제가 있습니다. 실제 사용 사례에 따라 지연시킬 수 있습니다. https://jsfiddle.net/37feyy6b/2/ 또는 웹 작업자 –

    +1

    * 시도한 방법은 무엇입니까? 지정하지 않으면 동일한 조언을 다시 받아야합니다. – JJJ

    +0

    @Juhana, 나는 내가 실패한 시도의 일부를 추천했다. – Dimos

    답변

    0

    드디어 내 코드에서와 같이, 수동으로 다시 흐름 이벤트를 트리거하는 경우에도,이 이벤트는 이벤트 큐에 추가되는 것 같다. 윈도우 당 자바 스크립트 스레드는 1 개 뿐이므로이 이벤트는 실행 코드가 완료된 경우에만 처리됩니다.

    이 동작에 대한 공식 문서를 찾을 수는 없지만 제안 된 기술로 동기 리플 로우 (일부 코드가 실행되는 동안)를 트리거 할 수 없었습니다. 그래서, 유일한 해결책은 작은 타임 아웃을 추가하는 것으로 보인다. 그래서 스레드는 작은 기간 동안 유휴 상태이며 나머지 코드 실행을 시작하기 전에 리플 로우 이벤트를 처리 할 수있다 (@Dan Smolinske가 제안한 것처럼).

    function executeWithLoader(callback) { 
        $("#test").show(); 
        setTimeout(function() { 
         callback(); 
         $("#test").hide(); 
        }, 50, this); 
    } 
    

    를 다음과 같은 방법으로 실행한다에게 클래스 처리를이 함수를 호출 :

    곤혹 다른 기능을 피하기 위해서, 하나는 다음과 같이 새로운 방법 executeWithLoader을 만들 수

    function processing() { 
        console.log("Processing started"); 
        var sum = 0; 
        for(i = 0; i < 100000000; i++) { 
         sum += i; 
        } 
        console.log("Processing ended"); 
    } 
    executeWithLoader(processing); 
    

    나는 이것을 받아 들인 응답으로 지금 남겨 두지 만, 리 플로우를 유발하는 성공적인 방법을 설명하는 미래의 대답이 있다면, 나는 그것을 바꿀 것이다.

    0

    대기 시간에 "0"매개 변수를 사용하여 setTimeout을 사용하면 표시/숨기기가 작동 할 수있을만큼 길게 중지됩니다.

    https://jsfiddle.net/o3y60e0L/3/

    $("#test").show(); 
    var t = $("#test")[0].offsetHeight; 
    console.log("Processing started"); 
    setTimeout(function() { 
        var sum = 0; 
        for(i = 0; i < 1000000000; i++) { 
         sum += i; 
        } 
    
        console.log("Processing ended"); 
        $("#test").hide(); 
    }, 0); 
    
    +0

    은'setTimeout' 대신에 ['requestAnimationFrame'] (https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)을 살펴볼 수 있습니다. 공연 목적으로. –

    +0

    질문 설명에 추가 된 것처럼 시간 초과가있는 솔루션에는 관심이 없습니다. 이것은 타임 아웃이 워크 플로를 복잡하게 만들 것이기 ​​때문에 (여기서는 로더 기능이 타임 아웃의 처리 코드와 결합되어 바람직하지 않다.) 내 경우에는 다른 문제가 발생하기 때문에 여기서는 설명하기 쉽지 않다. 그래서, 리플 로우를 강제하는 작업 방식을 찾고 있습니다. – Dimos

    관련 문제