" JScript - 脚本块"和内存泄漏 - 如何正确释放资源?

时间:2012-02-20 16:53:51

标签: jquery asp.net-mvc jquery-ui memory-leaks jquery-ui-tabs

我在项目的部分视图中放了一些jquery选项卡。我注意到Visual Studio的“解决方案资源管理器”,在调试期间每次单击新选项卡时都会生成一个新的动态JScript - script block

即使我将$('#mytabs .ui-tabs-hide').children().remove();$(".ui-tabs-hide").empty();放在标签的show事件中,也会发生这种情况。 脚本块包含我放在标签调用的部分视图中的javascript,所以每次单击以前单击的标签时,都会出现一个新的JScript块:很明显这会导致稳定性或内存泄漏问题...例如,我已经注意到在加载选项卡两次后,某些计时器和绑定无法正常工作。

我不知道问题是否由调用包含脚本的部分视图的方式引起。请注意我如何设置控制器操作(示例中的索引)。

这是我的环境:jquery 1.6.4 - jquery-ui 1.8.16 - IE 8.0.7601 我无法使用其他浏览器进行调试,因为Visual Studio似乎没有附加其进程并且不显示动态数据......

CONTROLLER

以下是标签调用的动作示例

  public ActionResult Index()
    {
         if (Request.IsAjaxRequest())
            return PartialView("_Index");

        return View(); 
    }

以下是我的观点和脚本的部分内容:

_Layout.cshtml

 ....
 <div id="body">  
    @Html.Partial("_TabsMenu");
 </div>
 ....

_TabsMenu.cshtml(包含标签菜单的部分视图)

 <div id="menutabs" class="content-wrapper">
    <ul >
        <li>@Html.ActionLink("Home", "Index", "Home")</li>
        <li>@Html.ActionLink("Test", "Index", "Test")</li>
         ...
    </ul>
 </div>

 <script type="text/javascript">
 $(function () {
     $('#menutabs').tabs({
         cache: false,
         show: function (event, ui) {
             $('#menutabs .ui-tabs-hide').children().remove(); // the content is removed , but the script is still in memory
             $(".ui-tabs-hide").empty(); // the content is removed, but the script is still in memory
         },
         select: function (event, ui) {
             $(window).unbind(); 
         }
     });
 });

(我甚至尝试将脚本放在div id中,pheraps很傻,但我想看看DOM中的脚本是否已被删除......但没有任何内容)

Index.cshtml

  @{Html.RenderPartial("_Index");}

_Index.cshtml(包含问题的重复jscript对象的局部视图)

   <table id="list4"></table>
   <jQuery("#list4").jqGrid({
datatype: "local",
height: 250,
colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
colModel:[
    {name:'id',index:'id', width:60, sorttype:"int"},
    {name:'invdate',index:'invdate', width:90, sorttype:"date"},
    {name:'name',index:'name', width:100},
    {name:'amount',index:'amount', width:80, align:"right",sorttype:"float"},
    {name:'tax',index:'tax', width:80, align:"right",sorttype:"float"},     
    {name:'total',index:'total', width:80,align:"right",sorttype:"float"},      
    {name:'note',index:'note', width:150, sortable:false}       
],
multiselect: true,
caption: "Manipulating Array Data"});
            var mydata = [
    {id:"1",invdate:"2007-10-01",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"2",invdate:"2007-10-02",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"3",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"4",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"5",invdate:"2007-10-05",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"6",invdate:"2007-09-06",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"7",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"8",invdate:"2007-10-03",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"9",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"}
    ];
       for(var i=0;i<=mydata.length;i++)
    jQuery("#list4").jqGrid('addRowData',i+1,mydata[i]);

更新

JScript - 脚本块1..N //这是我在每个JScript脚本块中看到的,在调试期间......我是testint jqgrid。这是demo from Trirand's site

     <jQuery("#list4").jqGrid({
datatype: "local",
height: 250,
colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
colModel:[
    {name:'id',index:'id', width:60, sorttype:"int"},
    {name:'invdate',index:'invdate', width:90, sorttype:"date"},
    {name:'name',index:'name', width:100},
    {name:'amount',index:'amount', width:80, align:"right",sorttype:"float"},
    {name:'tax',index:'tax', width:80, align:"right",sorttype:"float"},     
    {name:'total',index:'total', width:80,align:"right",sorttype:"float"},      
    {name:'note',index:'note', width:150, sortable:false}       
],
multiselect: true,
caption: "Manipulating Array Data"});
            var mydata = [
    {id:"1",invdate:"2007-10-01",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"2",invdate:"2007-10-02",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"3",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"4",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"5",invdate:"2007-10-05",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"6",invdate:"2007-09-06",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"},
    {id:"7",invdate:"2007-10-04",name:"test",note:"note",amount:"200.00",tax:"10.00",total:"210.00"},
    {id:"8",invdate:"2007-10-03",name:"test2",note:"note2",amount:"300.00",tax:"20.00",total:"320.00"},
    {id:"9",invdate:"2007-09-01",name:"test3",note:"note3",amount:"400.00",tax:"30.00",total:"430.00"}
    ];
       for(var i=0;i<=mydata.length;i++)
    jQuery("#list4").jqGrid('addRowData',i+1,mydata[i]);                

3 个答案:

答案 0 :(得分:8)

由浏览器解析的脚本不在DOM中,您无法“删除”它 - 变量仍然被定义,事件仍然被绑定,方法仍然存在。如果您将javascript放入重复加载的部分视图中,您将重复获取该javascript。

您需要做的是让您的javascript更具弹性。如果您将事件绑定到动态区域之外的元素 - 请不要。你会多次绑定它们。将该代码移动到仅加载一次的位置。尽量保持动态区域中的javascript独立,这样它只处理动态区域中的元素。

您还可以使用简单的if检查,使用更具范围的jquery选择器等来防止多个定义。

如果没有重复阻止内容的详细信息,我可以提供的内容并不多。

答案 1 :(得分:3)

在我看来,你的问题就是每次加载一个标签时,其中的所有脚本都会被加载,就我而言,你无能为力,记住你可以使用它服务器端代码生成这些脚本,因此ASP.NET必须采取行动,因为它们都是不同的(因为它们实际上可以是)。

然而,javascript是垃圾收集所以我不认为你看到的那些脚本实际上占用了用户的内存,而不是调试,调试器将始终显示已加载的所有内容,无论它是否被垃圾收集(尽管我实际上没有测试过它。)

如果你担心内存,只要确保你没有声明永远不会被垃圾收集的全局函数和变量(特别是在重新加载的范围内),为此,只需用

包围它们。

(函数(){

})();

因此,他们处于匿名函数中,可以在执行后立即进行垃圾收集。

答案 2 :(得分:2)

您只需要在文档就绪事件中收集选项卡中的所有脚本。下面的代码查找元素的所有脚本子项,执行它们然后销毁它们,因此它们不能再次执行:

function GlobalEvalScriptAndDestroy(element) {
var allScriptText = CollectScriptAndDestroy(element);
jQuery.globalEval(allScriptText);}



function CollectScriptAndDestroy(element) {
var allScriptText = "";
if (element.tagName == "SCRIPT") {
    allScriptText = element.text;
    $(element).remove();
}
else {
    var scripts = $(element).find("script");
    for (var i = 0; i < scripts.length; i++) {
        allScriptText += scripts[i].text;
    }
    scripts.remove();
}
return allScriptText;}