Javascript 单页应用程序中的DOM节点不断增加

Javascript 单页应用程序中的DOM节点不断增加,javascript,jquery-mobile,backbone.js,cordova,handlebars.js,Javascript,Jquery Mobile,Backbone.js,Cordova,Handlebars.js,我正在开发一个使用主干网、把手和jquery mobile的单页应用程序。我面临一个问题,导致DOM节点不断上升,无论我如何清理它们 为了更好地演示这个问题,我创建了一个简单的程序,它的结构与我的应用程序完全相同,并且存在相同的问题。整个应用程序只有4个文件: index.html: <!doctype html> <html> <head> <script id="home-tpl" type="text/x-handlebar

我正在开发一个使用主干网、把手和jquery mobile的单页应用程序。我面临一个问题,导致DOM节点不断上升,无论我如何清理它们

为了更好地演示这个问题,我创建了一个简单的程序,它的结构与我的应用程序完全相同,并且存在相同的问题。整个应用程序只有4个文件:

index.html:

<!doctype html>
<html>
    <head>
        <script id="home-tpl" type="text/x-handlebars-template">
        {{> header}}            
            <div data-role="content">       
                <a id="page1Link" href="#page1" data-role="button">goto Page1</a>
            </div>  
        {{> footer}}
        </script>
        <script id="page1-tpl" type="text/x-handlebars-template">
        {{> header}}
            <div data-role="content">       
                <h1>Hello, am I leaking?</h1>   
            </div>      
        {{> footer}}
        </script>       
        <script id="header-partial" type="text/x-handlebars-template">
            <div id="header" data-id="myHeader" data-role="header" data-position="fixed"              data-theme="a">
                <a href="#home" data-icon="arrow-l">Back</a>                                 
                <h1>{{pageTitle}}</h1>                                                  
            </div>
        </script>       
        <script id="footer-partial" type="text/x-handlebars-template">
            <div id="footer" data-id="myFooter" data-role="footer" data-position="fixed"  data-theme="a">           
                <h4>Copyright Stuff</h4>                                          
            </div>  
        </script>

        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="lib/jquery-1.8.3.js"></script>
        <script src="lib/jquery.mobile/jquery.mobile-1.4.2.min.js"></script>
        <script src="lib/jquery-ui-1.10.4.custom.min.js"></script>
        <script src="lib/underscore-min.js"></script>
        <script src="lib/backbone-min.js"></script>
        <script src="lib/backbone.touch.min.js"></script>
        <script src="lib/handlebars.js"></script>       

        <script src="templates/homeView.js"></script>
        <script src="templates/page1View.js"></script>

        <script src="js/main.js"></script>  

        <link rel="stylesheet" type="text/css" href="css/jquery-ui-1.10.4.custom.min.css" />
        <link rel="stylesheet" type="text/css" href="css/jquery.mobile-1.4.2.min.css"/>     
    </head> 
    <body></body>
</html>
homeView.js

var HomeView = Backbone.View.extend({

    template: Handlebars.compile($("#home-tpl").html()),

    render:function (eventName) {
        $(this.el).html(this.template({pageTitle:"home"}));         
        return this;
    },

    events : {
        "tap #page1Link" : "gotoPage1",
    },

    gotoPage1 : function() {  
        Backbone.history.navigate('page1', {trigger: true});
    }
});
var HomeView = {
....
initialize: function () {
    this.$el = $("#myviewport");
},
....
};
page1View.js

var Page1View = Backbone.View.extend({

    template: Handlebars.compile($("#page1-tpl").html()),

    render:function (eventName) {
        $(this.el).html(this.template({pageTitle: "page1"}));
        return this;
    },

    events : {
        "click div#header a" : "back",
    },

    back : function() {
        Backbone.history.navigate('home', {trigger: true});
    },
});
如果我在两个视图之间不断更改,DOM节点计数将显示以下行为(图形中内存下降的部分是我单击以强制垃圾收集的部分):

我是这些技术的初学者,所以我想我做错了什么。我已经找到了这个问题的答案,但我所能找到的都已经找到了(为每个被销毁的视图调用remove()和unbind())


那么,我如何处理这些节点呢?

我想您还没有删除$.mobile.changePage上引用的节点

  $.mobile.changePage($(page.el), {transition: transition, reverse: reverse});
但是,我不熟悉jquery mobile。但是我对backbonejs代码有一些评论

我的建议是在index.html上添加一个DIV元素,作为应用程序的查看端口。然后,所有视图对象都可以绑定到此DIV

index.html

<div id="myviewport"></div>
此外,还可以执行类似于渲染的操作

//main.js
//since page.render() return this, you can chain them up
//In other 
$("body").append(page.render().$el);
取消LegateEvents是取消所有事件的主干的主要方法
主干。验证。解除绑定(此);取消绑定主干验证

我从未使用过backbone.js或handlebar.js,但我看到您在close()函数中使用了这个.remove()。问题是,调用该函数时,“this”对象是什么。如果它是一个jQuery DOM对象,那么这个.remove()应该将它从DOM中删除。我会在该语句处停止调试器,并在调用close()时检查“this”是什么。此外,请检查Chrome Dev Tools中的“元素”选项卡,以确认在调用.remove()之后,预期的DOM元素正在被删除。我已经检查了“元素”选项卡,DOM正在被删除。我还不知道如何在javascript中使用调试器,但如果打印“this”,它会显示:
s{cid:“view7”,$el:jQuery.fn.jQuery.init[1],el:div.ui-page.ui-page-theme-a.ui-page-header-fixed.ui-page-footer-fixed.ui-page-ac‌​tive,constructor:function,template:function…}
。无需在每次处理路由时创建新视图。创建一次视图,然后在需要时更新。如果您需要从一个“页面”更改为另一个,只需清空el的html并将其他内容呈现到其中。另外,我不会重新定义已经为您定义的remove方法,因为主干视图已经在为您执行一些清理(解除绑定事件并从DOM中删除el)。我可以尝试只创建一次视图,但我认为清理代码是正确的,就像解释的那样。我不明白
$.mobile.changePag
是如何泄漏内存的。我用的方法和他们主页上的例子一样,只是一个猜测。由于已调用this.close()和this.unbind()来取消对主干视图和jquery上dom节点的引用,因此剩余的引用是传递给$.mobile的引用。
//main.js
//since page.render() return this, you can chain them up
//In other 
$("body").append(page.render().$el);
 Backbone.View.prototype.close = function() {
                    this.undelegateEvents();
                    Backbone.Validation.unbind(this);
                    this.$el.removeData().unbind().empty();
                    if (this.model) { 
                        this.model.off();
                        this.model.destroy({ silent: true }); 
                    }
};