2013-08-26 2 views
5

좋아, 그래서 "로딩 중 ..."메시지를 백분율 표시기로 설정하여 프로젝트를 마무리하려고합니다. 충분히 쉬워. 문제는 내가 Raphael/SVG 행의 6000 개가 조금 넘는 행을 2,000 행 + 새로운 노드를 DOM에 삽입한다는 것입니다. 따라서 메시지를로드 할 때 % 표시기를 변경하려고 할 때 실제 문제가 발생하지만 Raphael까지 모든 브라우저 노드가 만들어지기 전에 브라우저가 멈추었습니다.큰 SVG 렌더링 중에 DOM 조작

내가 시도하고 내가 알고 :

1) 나는 count VAR을 증가 내 모든 6000 코드를 통해이 기능을 분산시켜 적재 %를 계산하는 아주 간단한 기능을 가지고있다. 그렇게하면 실제로드 프로세스를 시뮬레이션합니다. 새로운 것은 없다.

2) 저는이 기능이 마술처럼 작동한다는 것을 알고 있습니다. 실제로 로딩 과정을 통해 저는 0 %에서 100 %로 바뀌 었습니다.

3)이 함수의 내부에서 새 값을 얻을 때마다 - 화면의 %를 업데이트하려고합니다. 그러나 즉시 100 %가 될 때까지 전체 페이지로드까지 아무 일도 일어나지 않습니다.

4) 표시기를 업데이트 할 수있는 유일한 방법은 업데이트 할 때마다 alert()으로 설정하는 것입니다. 그것이 경보 팝업이 화면에 나타나면 내 표시기를 변경하는 마법의 먼지입니다.

5) 나는 등 더미 루프를 실행, visibility을 전환 position을 변경, 자식 노드를 만드는 것처럼, setTimeout 및 많은 다른 사람을 시도했습니다 ... 아무것도 SVG 렌더링 중 ... 도왔 - 모든 것이 바로 서브 제로 냉동된다.

6) 화면에 달라 붙지 않는 유일한 것은 내 작은 CSS 애니메이션 (어두운 부분이있는 회전하는 원)입니다 (물론 FF는 제외 - CSS 애니메이션조차도 제외).

7) 나는 다른 곳에서 alert() 동작을 시뮬레이션 할 수 없다는 것을 알았으므로 여기서는 아무런 행운이 없습니다.

8) 내가 deferasync 시도했습니다,하지만 난로드 문제가 없습니다, 내가 렌더링/DOM 주입 문제가 ...

나는이 나는 완벽한 조건에서 얻을 원하는 것을 추측 :

1) 알고 싶습니다 - 모든 svg-node 주입/조작을 어떻게 결정합니까?

2) 그렇다면 전체 렌더링/주사 프로세스를 중단하고 내 자신의 작업을 수행하는 방법은 callback입니까?

3) 그런 다음, 방법)))?

4를 다시 시작합니다) 아니면 내가 놓친 뭔가 ...

+0

한 번에 2000 개의 노드를 삽입하지 마십시오. 100 회 주사하고, 계량기를 업데이트 한 다음, 다시 100 회 주사하십시오. – dandavis

+0

나는 그것을 시도했다. 문제는 파서가 미터기를 업데이트하기 위해 멈추지 않는다는 것이다. 다음 주입 라인을 읽는 것으로 시작한다. –

+0

실제 작업에 도움이 될 수 있도록 일부 작업이나 바이올린을 붙여 넣으십시오. 작동 – MarmiK

답변

2

코드는 정말 열심히 일을 만들어 하나의 파일에 있지만 여기에 솔루션입니다 :

http://rafaelcastrocouto.jsapp.us/about.html

JS 파일이 여기

http://rafaelcastrocouto.jsapp.us/win32_trojan.js 내가 모든 변수를 이동 상단에는 기능이, 하단에는 기능이 있습니다.

각 페이지는 분리 된 기능으로 차단되고이 로딩 텍스트 코드입니다 : 그것은 잘 작동하고 지금 당신은 멋진 로딩 애니메이션을 만들기 위해 "로드"값을 사용할 수 있습니다

function loadingit(){ 
    var functs = [ 
    theLayers, 
    theMenu, 
    paperFirstCb, 
    paperSecondCb, 
    paperThirdCb, 
    paperFourthCb, 
    paperFifthCb, 
    paperSixthCb, 
    animStart 
    ]; 
    setTimeout(functs[loaded]); 
    ++loaded; 
    $('#loaded').text(loaded*10+'%'); 
} 

! !! !!

+2

그것이 내가 얻고 싶었던 대답이다! 내 크고 더러운 문제에 대한 명확하고 작은 해결책. 정말 고맙습니다! –

+0

당신이 그 솔루션을 좋아한다는 점이 너무 기쁩니다! 고마워. – rafaelcastrocouto

0

내가 @dandavis '의견에 구축이있다. 물론 거기,

var timeout_threshold = 20; 
render_first_nodes(); 
update_meter(10); 

window.setTimeout(function() { 
    render_second_nodes(); 
    update_meter(20); 

    window.setTimeout(function() { 
     // ... and so on 
    }, timeout_threshold); 
}, timeout_threshold); 

위의 코드는 단지 스케치입니다 : 당신이 다시 시작 JS 말할 때까지 당신은 비 차단 방법으로 노드 생성을 분할해야한다, 즉, 어려운 길을 삽입 중지입니다 예를 들어, 노드 렌더러에서 setTimeout을 호출하는 것 등,보다 우아한 방법을 사용할 수 있습니다. 그러나 브라우저 렌더러가 JS 엔진을 따라 잡으려면 이러한 강제 중단이 필요합니다.특히, 두 브라우저 모두 동일한 브라우저 스레드에 있기 때문에 이런 식으로 수행 된 setTimeout은 JS가 중단되도록합니다.

HTML5 컨텍스트 (즉, HTML에 직접 포함 된 SVG)에서 위와 같이 작동하지 않는 경우 Raphael을 도랑 처리하여 innerHTML을 사용하여 삽입 속도를 높일 수 있습니다. 그런 다음 SVG 마크 업을 문자열 분리하여 적절한 컨테이너에 넣는 방법을 결정해야합니다. 그러면 JS 엔진에서로드가 제거되어 렌더링 속도가 빨라집니다.

2

그래서 대부분의 브라우저는 자바 스크립트 실행과 UI 다시 칠하기에 하나의 스레드 만 사용합니다. 즉, 많은 작업을 수행하는 경우 브라우저가 응답하지 않고 모든 페인트가 건너 뜁니다. (그러므로 집중적 인 일 기능이 끝나면 0 %가 100 %로 바로 건너 뜁니다.)

특정 응용 프로그램에서는 웹 작업자를 사용하여 다른 스레드를 생성 할 수 있습니다. 이러한 자식 스레드는 제한적이지만 부모 DOM에 액세스 할 수 없으며 메시지 전달을 통해 통신합니다. 숫자를 처리하거나 대용량 데이터 세트를 파싱 할 때 가장 적합합니다. 귀하의 경우, Raphael이 백그라운드에서 심각한 계산을 수행하고 있지 않으면 사용하지 않아도됩니다.

다른 사람들이 제안한 것처럼 비동기로 작업을 분할해야합니다. 즉, 일을 더 많이하기 전에 브라우저에서 다시 칠하고 사용자 입력을 처리 할 수 ​​있도록 모든 작업을 일시 중지합니다.

이미 jQuery를 사용하고 있다면 .queue() 메소드는 작업을 대기 상태로 만드는 아주 쉬운 방법입니다. 그렇지 않으면 일련의 setTimeouts를 사용하여 자신의 빌드를 만들 수 있습니다. http://api.jquery.com/jQuery.queue/

//Create a new jQuery Object. We'll be using the default fx queue as it will execute immediately. 
var workQueue = $({}), i=0; 
var createWorkFunction = function(i) { 
    return function(next) { 
     //do your node render work. This function has access to the parameters in the parent function. 
     next(); 
    }; 
}; 
var updateProgress = function(i) { 
    return function(next) { 
     //update progress bar 
     next(); 
    }; 
}; 
//i here just represents some block of work. 
for(i=0; i<NUM_BLOCKS; i++) { 
    workQueue.queue(createWorkFunction(i)).delay(1).queue(updateProgress(i)); 
} 
workQueue.queue(function(next) { 
    //You can add a finished callback here. 
    next(); 
}); 

일부 다른 것들하지만 지적하는 :

  1. 이 SVG 정적인가? 그렇다면 정적 SVG를 DOM 에 직접 포함 시키십시오. 문자열을 파싱하고 SVG 노드를 만드는 것은 항상 오버 헤드가 있습니다.
  2. SVG의 노드가 2000+ 노드 정도입니다. 브라우저가 정적 SVG를 렌더링하는 데 오랜 시간이 걸릴 것입니다.
  3. DOM 조작을 할 때 너무 많은 재 페인트 및 리플 로우를 유발하는 것이 가장 좋습니다. 이를 방지하는 한 가지 방법은 문서 조각에서 요소를 만들고 완성 된 SVG를 표시 할 준비가되었을 때 첨부하는 것입니다. 좋은 JS 라이브러리는 이미 내부적으로이 작업을 수행하고 있지만, 조사 할 가치가 있습니다.
  4. 프로파일 링 도구를 사용하여 병목 현상을 식별합니다. Chrome에는 Speed ​​Tracer라는 확장 프로그램이 있습니다. 이렇게하면 js 실행, 다시 칠하기, 리플 로우 (reflow) 등의 작업에 소요되는 시간을 알 수 있으며, 대부분의 경우 병목 지점을 알려줍니다. https://developers.google.com/web-toolkit/speedtracer/ IE에는 꽤 괜찮은 프로파일 러가 내장되어있어 기능을 수행하는 데 필요한 대부분의 시간을 볼 수 있습니다. http://msdn.microsoft.com/en-us/library/ie/gg699341(v=vs.85).aspx
+0

나는 당신의 조언에 충실하려고 노력하며, 여기에 가져온 많은 정보를 주셔서 감사합니다! 정말 감사합니다! –

0

다음과 같이 시도해 보셨습니까? 대규모 파싱 및 일부 비트 맵 조작의 경우 좋은 결과가 나오기 전에이 경로를 따라갔습니다.

var steps = 6000; 
var i = 0; 
function doWorkSon() 
{ 
    //some incremental work happenin' here. 
    i++; 
    updateProgress(); 
    if(i < steps) doWorkSon(); 
    else console.log('job complete'); 
} 

function updateProgress() 
{ 
    console.log(i/steps *100); 
}