2013-07-01 4 views
1

EDIT : Firefox에서만 발생합니다! (22.0을 사용하고 있습니다.) 하단의 브라우저 비교를보십시오.파이어 폭스에 대한 재귀 호출이

픽셀 데이터를 복사하고 점진적으로 알파 값을 255에서 0으로 변경하면 (배경이 검은 색) 캔버스에 '검은 색 페이드'효과를 만들려고합니다.

function fadeToBlack() { 
    if(typeof this.recursion === 'undefined' || this.recursion === 0) { 
     this.recursion = 1; 
     this.imageData = this.ctx.getImageData(0, 0, this.width, this.height); 
     this.imageDataArray = this.imageData.data; 
     this.pixelCount = this.imageDataArray.length/4; 
     this.fadeToBlack(); 
    } 
    else if (this.recursion <= 15){ 
     console.time('Change alpha ' + this.recursion); 
     for (var i = 0; i < this.pixelCount; i++){ 
      this.imageDataArray[i * 4 + 3] = 255 - 255/15 * this.recursion; 
     } 
     console.timeEnd('Change alpha ' + this.recursion); 
     this.ctx.putImageData(this.imageData, 0, 0); 
     this.recursion++; 
     setTimeout(function(){ 
      this.fadeToBlack(); 
     }.bind(this), 50); 
    } 
    else { 
     this.recursion = 0; 
    } 
}; 

나는 (! 1280 * 1024 = 1310720 반복)이 정말 비싼 것이라고 생각하지만, 아래의 콘솔 로그에서 볼 수 있듯이, 그것은 첫 번째 반복을 제외하고 놀라 울 정도로 빨랐다. 단순히 fadeToBlack (화소 조작 첫번째 반복)의 두 번째 반복 ... 지연 경우

Change alpha 1: 543ms 
Change alpha 2: 16ms 
Change alpha 3: 6ms 
Change alpha 4: 16ms 
... 

이상하게 마법

function fadeToBlack() { 
    if(typeof this.recursion === 'undefined' || this.recursion === 0) { 
     this.recursion = 1; 
     this.imageData = this.ctx.getImageData(0, 0, this.width, this.height); 
     this.imageDataArray = this.imageData.data; 
     this.pixelCount = this.imageDataArray.length/4; 
     //This is the only difference! 
     setTimeout(function(){ 
      this.fadeToBlack(); 
     }.bind(this), 0); 
    } 
    else if (this.recursion <= 15){ 
     console.time('Change alpha ' + this.recursion); 
     for (var i = 0; i < this.pixelCount; i++){ 
      this.imageDataArray[i * 4 + 3] = 255 - 255/15 * this.recursion; 
     } 
     console.timeEnd('Change alpha ' + this.recursion); 
     this.ctx.putImageData(this.imageData, 0, 0); 
     this.recursion++; 
     setTimeout(function(){ 
      this.fadeToBlack(); 
     }.bind(this), 50); 
    } 
    else { 
     this.recursion = 0; 
    } 
}; 

뭔가 일어난다.

Change alpha 1: 16ms 
Change alpha 2: 16ms 
Change alpha 3: 6ms 
Change alpha 4: 6ms 
... 

그래서 도대체 무슨 일이 벌어지고있는거야?

EDIT : 나는 여러 브라우저에서이를 테스트했으며, 15 회 반복마다 밀리 초 단위로 결과를 보았습니다.

Browser |Recursive |Asynchronous 
=========+===========+============ 
Firefox |1652†  |1136 
Chrome |976  |978 
Opera |12929  |13855 
IE  |855  |854 

첫 번째 반복 매우 비용 (500ms로)이었다 †.

+0

이후 백그라운드에서. 다시는 재귀가 아닙니다. 반환하는 값에 의존하지 않아도됩니다. 그 부스트의 이유를 알고 싶습니다. 비동기 호출을 호출하고 메모리에서 현재를 제거하고 대기열과 관련이없는 것으로 간주하는 현재 호출을 마칠 때입니까? – CME64

+0

질문을 던질 때 비동기식/재귀형에 조금 퍼지기는했지만 지금은 조금 읽었습니다 ... 성능 향상이 어디에서 발생하는지 아직 알지 못합니다. 나는 아마도 같은 엔진에서 동일한 5mB 데이터 세트 (this.imageData)에 동시에 액세스 할 수있는 2 개의 함수를 사용하는 것과 관련이 있습니다. 다른 브라우저에서 몇 가지 테스트를 수행하고 어떤 결과가 발생하는지 볼 수 있습니다. – LittleJohn

+0

@ CME64 완료! 확실히 엔진 버릇처럼 보입니다! – LittleJohn

답변

1

나는 함수가 죽을 때까지 (setTimeout을 사용하여 비동기 호출을 사용할 때) 한 번만 호출하기 때문에 함수 사이의 점프를 절반으로 줄인다 고 생각하지만, 내부에서 호출하여 재귀를 사용하면 그 시점에서 중단됩니다 마지막 호출이 끝날 때까지 다음 호출로 점프하는 등 점진적으로 재귀를 수행하여 재귀에서 반환 된 값을 사용하여 계속 진행하고 이전 함수로 돌아가려면 중지 된 줄에서 이전 함수를 호출합니다. 실적 및 방법론에서 입찰가 차이를 볼 수 있습니다. 나는 그것이 당신에게 내가 의심 할 수없는 동일한 결과를 주는지 물어보아야한다.

TL, DR setTimeout : 비동기 호출 (독립), 재귀 : 동기 (종속).

그래픽 데모 :

이상하다,하지만 당신은 당신이 함수는 비동기 실행하고 있습니다에서는 setTimeout 사용하면 현재 함수 실행 큐에서 다음 호출을 넣는 동안 작업을 계속합니다

enter image description here

관련 문제