EDIT: Only occurs in Firefox! (I'm using 22.0) See the browser comparison at the bottom.
I'm trying to create a 'fade to black' effect on the canvas by copying the pixel data and progressively changing the alpha values from 255 to 0 (the background is black).
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;
}
};
I thought this would be really expensive (1280 * 1024 = 1310720 iterations!), but as you can see from the console log below, it was surprisingly quick except for the first iteration.
Change alpha 1: 543ms
Change alpha 2: 16ms
Change alpha 3: 6ms
Change alpha 4: 16ms
...
Curiously, if I simply delay the second iteration of fadeToBlack
(first iteration of the pixel manipulation)...
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;
}
};
Something magical happens.
Change alpha 1: 16ms
Change alpha 2: 16ms
Change alpha 3: 6ms
Change alpha 4: 6ms
...
So what the heck is going on here?
EDIT: I tested this in several browsers and here are the results in milliseconds for all 15 iterations.
Browser |Recursive |Asynchronous
=========+===========+============
Firefox |1652† |1136
Chrome |976 |978
Opera |12929 |13855
IE |855 |854
†First iteration was very expensive (500ms).