1

編集: 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 回の反復!)、以下のコンソール ログからわかるように、最初の反復を除いて驚くほど高速でした。

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

fadeToBlack不思議なことに、 (ピクセル操作の最初の反復)の 2 回目の反復を単純に遅らせると...

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

†最初の反復は非常にコストがかかりました (500ms)。

4

1 に答える 1

1

関数が終了するまで一度だけ呼び出すため(setTimeoutを使用して非同期呼び出しを使用する場合)、関数間のジャンプが半分に減少すると思いますが、内部から呼び出して再帰を使用すると、その時点で停止し、にジャンプします次の呼び出しなど、最後の呼び出しが完了するまで、徐々に再帰に進み、停止した行から前の関数を呼び出して、再帰から返された値を使用し続け、前の関数に戻る、入札を見ることができますパフォーマンスと方法論の違い。そうでないと思うのと同じ結果が得られるかどうかを尋ねなければなりません。

TL;DR setTimeout: 非同期呼び出し (独立)、再帰: 同期 (依存)。

グラフィカルなデモンストレーション:

ここに画像の説明を入力

于 2013-07-01T04:36:48.250 に答える