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

将清理保持为新添加内容的镜像:

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

然后根据需要完全重绘列表。

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

经验法则:

  1. 如果你添加一些东西,在添加新东西之前将它从 dom 中完全删除。我不相信附加。

  2. jQuery 插件可以像水龙头一样泄漏内存。在运行测试之前,您可能需要先禁用所有插件。IE 8 在管理内存方面可能特别糟糕,因此为了获得最佳测试,请使用最差的浏览器。:)

  3. 使用 JSON 的静态副本进行测试。我可以看到 jQuery 在这里有点泄漏(尤其是使用 jsonp),所以您可能想要推出自己的 ajax 方法。完成后将所有回调/属性/对象设置为 null。Javascript 容易出现循环引用泄漏。

于 2013-03-04T05:43:13.063 回答
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 开始(目前它在首次加载时会快速连续运行两次。事实上,我认为您需要考虑一些延迟问题)。试试这种形式,它每 5 秒请求一次而不增加超时,并在下载后以秒为间隔执行一次更改,

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 回答