1

编辑:只发生在 Firefox 中!(我使用的是 22.0)请参阅底部的浏览器比较。

我试图通过复制像素数据并逐渐将 alpha 值从 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 次迭代!),但正如您从下面的控制台日志中看到的那样,除了第一次迭代外,它的速度非常快。

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

奇怪的是,如果我只是延迟fadeToBlack(像素操作的第一次迭代)的第二次迭代......

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
...

那么这里到底发生了什么?

编辑:我在几个浏览器中对此进行了测试,这里是所有 15 次迭代的毫秒结果。

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

†第一次迭代非常昂贵(500 毫秒)。

4

1 回答 1

1

我认为这将函数之间的跳转减少了一半,因为您只调用一次直到函数终止(使用 setTimeout 使用异步调用时),但是如果您通过从内部调用使用递归,它将在该点停止并跳转到下一次调用,依此类推,直到完成最后一次调用,然后逐渐递归,从它停止的行调用上一个函数,继续使用递归返回的值并返回到前一个,我可以看到一个出价性能和方法的差异。我要问它是否给你同样的结果,我怀疑不会是这样。

TL;DR setTimeout:异步调用(独立),递归:同步(依赖)。

图形演示:

在此处输入图像描述

于 2013-07-01T04:36:48.250 回答