0

メモリ リークと関数 $.getJSON および $.each ループに関する質問があります。定期的に更新される外部 JSON ファイルからデータを取得しています。2 つの関数を使用して JSON ファイルからデータを反復処理し、別の関数を使用して 5 つの順序付けられていないリストを使用してページに表示します。また、これらの反復を一時停止する関数を使用します。問題は、このスクリプトが大量のメモリと CPU リソースを消費することです。私の理解では、関数 .remove() はオブジェクトをメモリから削除するのではなく、DOM 構造から削除するだけです。ページに 5 つの UL を出力した後にメモリをクリーンアップし、メモリ リークを防ぐにはどうすればよいですか? また、私の一時停止機能はアニメーションを停止しますが、何らかの理由で.eachループを停止せず、メモリ消費の問題も引き起こします.Eachループを一時停止する方法はありますか? これは私のスクリプトです:

    <!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="content-type" content="text/html" />
    <meta name="author" content="Viacheslav" />
    <script src="js/jquery-1.7.1.min.js"></script>
    <title>JSON TEST-1</title>
</head>

<body>

  <div id="content_div">
        <ul></ul>  
  </div>
<input type=button value="pause/play" onclick="continue_reporting = ( continue_reporting == 1 ) ? 0 : 1;">
    <script type="text/javascript">        

        var counter = 0;
        var delay_entry = 0;
        delay_fetch = 0;
        var continue_reporting = 1;      
        var node_list = new Array( );
        //var content_div = $("#content_div");
        var child = 0;


        fetch_data(); // initial run
        function fetch_data()
        {

          $.getJSON('js/list.json?i=' + Math.random(), function(data){
              //console.log("data.length: " + data.length );
              $.each(data, function(key,value){
                counter++
                setTimeout( pusher, 1000 * delay_entry, value );
                delay_entry++;                

              })



          })  
          setTimeout( fetch_data, 1000 * delay_fetch );
          delay_fetch++;

        }

        function pusher( value )
        {      

            if ( continue_reporting == 1 ) 
            {
              $("#content_div").append("<ul>" + 
                                    "<li>" +  value.reg + "</li>" +
                                    "<li>" +  value.bids[0].ind + "</li>" +
                                    "<li>" +  value.bids[0].v + "</li>" +
                                "</ul>");
                child++;             

               if (child > 4){
              $("#content_div ul:first-child").remove();              
              }

              }
              console.log("children = " + child);

        }


    </script>



</body>
</html>
4

2 に答える 2

0

JavaScript でオブジェクトを削除することはできません。ガベージコレクション言語です。そうは言っても、何かを削除するときに参照を NULL にすることで実行する場合、ガベージ コレクターにとって物事を簡単にすることができます (これは、ガベージ メモリに参照ループが多すぎる場合に放棄する古い IE バージョンでは特に重要です)。 )。これは、よく管理されている (ループがない) DOM 構造にはあまり当てはまりませんが、変数には当てはまります。ガベージ コレクターは、ブラウザがメモリの使用量が多すぎると判断したときに実行されます。

JavaScript タイムアウトを一時停止することはできませんが、キャンセルして後で再開することはできます。たとえば、配列を作成できます。

var timers = [];

それを記入してください:

var tm = +new Date( );
(then in .each loop)
timers.push( {'ref': setTimeout( pusher, 1000 * delay_entry, value ), 'when': tm + 1000 * delay_entry, 'with': value} );

今、あなたはそれらをキャンセルすることができます:

var tm = +new Date( );
for( var i = 0; i < timers.length; ++ i ) {
    clearTimeout( timers[i].ref );
    timers[i].ref = undefined;
    timers[i].when -= tm;
}

それらを再起動します。

var tm = +new Date( );
for( var i = 0; i < timers.length; ++ i ) {
    if( timers[i].when > 0 ) {
        timers[i].ref = setTimeout( pusher, timers[i].when, timers[i].with );
    }
    timers[i].when += tm;
}

timers.shift() で処理するときは、配列をクリアすることを忘れないでください。

記憶に戻ると、いくつかの問題があります。まず、値をプッシュしてシフトアウトする適用する更新を格納するグローバル値を用意して、多くの参照が飛び回らないようにすることをお勧めします。次に、タイムアウトを単一の間隔 (setInterval) に変更して、上記のコードを意味のないもの (!) にレンダリングする必要があります。これは特に fetch_data の呼び出しに当てはまります。現時点では再帰があるため、大量のメモリが決して解放されないからです。また、delay_fetch を 1 から開始するように修正する必要があります (現在、最初のロード時に 2 回連続して実行されます。実際、遅延に関して考慮する必要がある問題がいくつかあると思います)。タイムアウトを増やすことなく 5 秒ごとにリクエストし、ダウンロード後に 1 秒間隔で一度に 1 つずつ変更を実装するこのフォームを試してください。

var delay_fetch = 5;
var node_list = [];
var child = 0;

function process_data(data){
    var delay_entry = 0;
    $.each(data, function(key,value){
        setTimeout( pusher, 1000 * delay_entry, value );
        delay_entry++;                
    })
}
function fetch_data(){
    $.getJSON('js/list.json?i=' + Math.random(), process_data);
}
setInterval( fetch_data, 1000 * delay_fetch );
于 2013-03-04T06:02:58.597 に答える
0

新しく追加されたコンテンツのミラー イメージとしてクリーンアップを保持します。

          $("#content_div").html(null);              
          // may add .remove() too to be safe.         

次に、必要に応じてリストを完全に再描画します。

          $("#content_div").html( yourNewContent );   

経験則:

  1. 何かを追加する場合は、新しいものを追加する前に dom から完全に削除してください。私は追加を信用しません。

  2. jQuery プラグインは蛇口のようにメモリをリークする可能性があります。テストを実行する前に、まずすべてのプラグインを無効にする必要がある場合があります。IE 8 は特にメモリの管理に問題があるため、最良のテストを行うには最悪のブラウザを使用してください。:)

  3. JSON の静的コピーを使用してテストします。ここでは (特に jsonp で) jQuery が少しリークしていることがわかるので、独自の ajax メソッドをロールすることをお勧めします。すべてのコールバック/プロパティ/オブジェクトが終了したら、null に設定します。Javascript は循環参照リークを起こしやすいです。

于 2013-03-04T05:43:13.063 に答える