JavaScriptで、再帰的な関数呼び出しのコールスタックサイズを減らす方法はありますか?

CrazyFluffyPony

キャンバスに描画する機能があります。この関数はいくつかの手間のかかる作業を行います。私が理解しているように、requestAnimationFrame()は呼び出しスタックをクリア/リセットしないため、この手間のかかる作業の変数はメモリに保持されます。

最近のFirefoxのアップデートでこの問題が発生しました(数秒以内に10GBを超えるRAMが使用されました)。以前のバージョンのFirefoxで動作し、Chromeでも動作するため、バグの可能性があります。しかし、それでも、これを自分で修正する方法や、より良いコードを書く方法があるかどうかを知りたいと思います。

前もって感謝します!

コード例:

"use strict";

class DrawUnit {
  constructor(canvas){
    this.canvas = canvas;

    window.requestAnimationFrame(()=>{
        this.draw()
    });
  }

  draw(){
    let data = generateAndProcessData(); //heavy lifting happening here, old data stays in memory because the previously called draw() still has a reference to it right?

    let ctx = this.canvas.getContext('2d');

    //reset canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for(let d of data){
        //draw some line
    }

    window.requestAnimationFrame(()=>{
        this.draw()
    })
  }
}

setTimeout()は同じ結果を提供しますが、私はrequestAnimationFrame()を使用することを好みます

問題と解決策は5行目の無名関数に関連していると思いますが、this.draw()自分で解決策を見つけることができませんでした。匿名関数を使用しない場合、実行コンテキストが失われますが、それが必要です!

TJクラウダー

draw実際には再帰的ではありません。Firefoxのコールスタックは、デバッグ目的の非同期ネストを含む概念的なコールスタックを示しています。実際のコールスタックは、draw戻るときにクリアされます。

渡すために作成しているクロージャーrequestAnimationFrameは、理論data的には、クローズする字句環境オブジェクトを介し間接的に参照を保持します。ブラウザはそのリンクを最適化できる場合とできない場合があります(ChromeなどのJavaScriptエンジンであるV8は、クロージャの最適化にかなり積極的でしたが、実行時間の影響のために、完全ではなく少し後退していました。それがあった)。

良いニュースは、以下を使用することで閉鎖を完全に回避できることbindです。

requestAnimationFrame(this.draw.bind(this));

bind呼び出されると、最初の引数がthis何であれ、元の関数を設定して呼び出す新しい関数を作成しますbind現在の状況では、クロージャは作成されません。

したがって、への呼び出し中に作成されたクロージャがないdrawためdata、以前の呼び出しから何も保持さません(最適化がない場合)。


requestAnimationFrameただし、あなたが与えるコールバックは決して重労働であってはなりません。非常に迅速に作業を行う必要がありますrAFコールバックに数ミリ秒以上かかる場合、ブラウザーはあなたに不平を言います。)

「重いリフティング」がCPU時間の点で重要な場合は、可能であればWebワーカーにオフロードpostMessageし、DOMにレンダリングするために最終データをメインスレッド()に送信することをお勧めします。messageイベントを処理するメインスレッドのコードは、次にペイントするときにブラウザによってペイントされるようにイベントをDOMにレンダリングします。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

1回のコールバック呼び出しだけで非同期呼び出しを再帰的に実行する方法はありますか?

分類Dev

すべての再帰呼び出しの前に、最終的な結果を返す再帰関数は、コールスタックからポップされています

分類Dev

ボタンクリック時にコードビハインドから複数のJavaScript関数を呼び出したい。3つのjavascript関数では問題なく動作しますが、それ以上ではありません

分類Dev

Nodejs-エラーコールバック時に関数を再呼び出しします-ノンブロッキングの方法はありますか?

分類Dev

コーディングインタビューのクラッキング:再帰サブセットアルゴリズムがインデックスを減らすのではなく増やすのはなぜですか?

分類Dev

コーディングインタビューのクラッキング:再帰サブセットアルゴリズムがインデックスを減らすのではなく増やすのはなぜですか?

分類Dev

私はREACTを初めて使用します。ボタンをクリックすると、別のファイルからソートクラスコンポーネント内にある関数resetArrayを呼び出す必要があります。

分類Dev

「Clang-Tidy:関数は再帰的な呼び出しチェーン内にあります」とは何ですか?それを修正する方法は?

分類Dev

この再帰関数を1回だけ呼び出す効率的な方法はありますか?

分類Dev

Flaskでは、複数のチェックボックスでHTML入力タグのさまざまな関数を呼び出す方法はありますか?

分類Dev

「最大呼び出しスタックサイズを超えました」を引き起こす再帰的なJavaScript関数

分類Dev

AJAX呼び出しでHTMLコンテンツとコールバック関数の両方を返す方法はありますか?

分類Dev

別の関数から取得した文字列でインデックス付けされたテーブル内の関数を呼び出すにはどうすればよいですか?また、引数を追加する必要がありますか?

分類Dev

Javascript:関数は、これまでに呼び出したすべての関数のすべてのコールバックを呼び出しますか?

分類Dev

スタックをオーバーフローさせることなく、非同期関数を再帰的に呼び出すことはできますか?

分類Dev

メンバー関数をコンストラクターから呼び出せないようにする方法はありますか?

分類Dev

メンバー関数をコンストラクターから呼び出せないようにする方法はありますか?

分類Dev

仮想なしで基本クラスポインタを使用して派生クラス関数を呼び出す方法はありますか?

分類Dev

単純な再帰関数を実行する際の最大呼び出しスタックサイズエラー

分類Dev

C ++の独自の定義からクラスメンバー関数を再帰的に呼び出す方法は?

分類Dev

クラウド関数から:再帰的なJavaScript関数を呼び出す方法は?

分類Dev

負の引数が渡されたときに、コードが再帰呼び出しでスタックするのはなぜですか?

分類Dev

ソースオブジェクトとして使用されるフォームで宣言されたパブリックサブルーチンを、メインフォームからサブフォームコントロールを呼び出すのに最適な方法はありますか?

分類Dev

httpリクエストでのコールバック呼び出しはどこにありますか(javascript)

分類Dev

JavaScriptサンプルコードは「UncaughtRangeError:最大呼び出しスタックサイズを超えました」を呼び出します

分類Dev

Dartは、ストリームがStreamControllerからのものであるstream.listen()からonDoneコールバックを呼び出す方法があります。

分類Dev

Dartは、ストリームがStreamControllerからのものであるstream.listen()からonDoneコールバックを呼び出す方法があります。

分類Dev

JavaScriptから関数の背後にあるコードを呼び出す(AJAXではありません!)

分類Dev

javascript再帰関数:Uncaught RangeError:最大呼び出しスタックサイズを超えました

Related 関連記事

  1. 1

    1回のコールバック呼び出しだけで非同期呼び出しを再帰的に実行する方法はありますか?

  2. 2

    すべての再帰呼び出しの前に、最終的な結果を返す再帰関数は、コールスタックからポップされています

  3. 3

    ボタンクリック時にコードビハインドから複数のJavaScript関数を呼び出したい。3つのjavascript関数では問題なく動作しますが、それ以上ではありません

  4. 4

    Nodejs-エラーコールバック時に関数を再呼び出しします-ノンブロッキングの方法はありますか?

  5. 5

    コーディングインタビューのクラッキング:再帰サブセットアルゴリズムがインデックスを減らすのではなく増やすのはなぜですか?

  6. 6

    コーディングインタビューのクラッキング:再帰サブセットアルゴリズムがインデックスを減らすのではなく増やすのはなぜですか?

  7. 7

    私はREACTを初めて使用します。ボタンをクリックすると、別のファイルからソートクラスコンポーネント内にある関数resetArrayを呼び出す必要があります。

  8. 8

    「Clang-Tidy:関数は再帰的な呼び出しチェーン内にあります」とは何ですか?それを修正する方法は?

  9. 9

    この再帰関数を1回だけ呼び出す効率的な方法はありますか?

  10. 10

    Flaskでは、複数のチェックボックスでHTML入力タグのさまざまな関数を呼び出す方法はありますか?

  11. 11

    「最大呼び出しスタックサイズを超えました」を引き起こす再帰的なJavaScript関数

  12. 12

    AJAX呼び出しでHTMLコンテンツとコールバック関数の両方を返す方法はありますか?

  13. 13

    別の関数から取得した文字列でインデックス付けされたテーブル内の関数を呼び出すにはどうすればよいですか?また、引数を追加する必要がありますか?

  14. 14

    Javascript:関数は、これまでに呼び出したすべての関数のすべてのコールバックを呼び出しますか?

  15. 15

    スタックをオーバーフローさせることなく、非同期関数を再帰的に呼び出すことはできますか?

  16. 16

    メンバー関数をコンストラクターから呼び出せないようにする方法はありますか?

  17. 17

    メンバー関数をコンストラクターから呼び出せないようにする方法はありますか?

  18. 18

    仮想なしで基本クラスポインタを使用して派生クラス関数を呼び出す方法はありますか?

  19. 19

    単純な再帰関数を実行する際の最大呼び出しスタックサイズエラー

  20. 20

    C ++の独自の定義からクラスメンバー関数を再帰的に呼び出す方法は?

  21. 21

    クラウド関数から:再帰的なJavaScript関数を呼び出す方法は?

  22. 22

    負の引数が渡されたときに、コードが再帰呼び出しでスタックするのはなぜですか?

  23. 23

    ソースオブジェクトとして使用されるフォームで宣言されたパブリックサブルーチンを、メインフォームからサブフォームコントロールを呼び出すのに最適な方法はありますか?

  24. 24

    httpリクエストでのコールバック呼び出しはどこにありますか(javascript)

  25. 25

    JavaScriptサンプルコードは「UncaughtRangeError:最大呼び出しスタックサイズを超えました」を呼び出します

  26. 26

    Dartは、ストリームがStreamControllerからのものであるstream.listen()からonDoneコールバックを呼び出す方法があります。

  27. 27

    Dartは、ストリームがStreamControllerからのものであるstream.listen()からonDoneコールバックを呼び出す方法があります。

  28. 28

    JavaScriptから関数の背後にあるコードを呼び出す(AJAXではありません!)

  29. 29

    javascript再帰関数:Uncaught RangeError:最大呼び出しスタックサイズを超えました

ホットタグ

アーカイブ