DOM节点在单页面应用程序中不断增加

时间:2014-04-02 18:31:28

标签: 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-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>

main.js:

var AppRouter = Backbone.Router.extend({

    routes:{
        "home":"home",
        "page1" : "page1",
    },

    home:function () {
        this.changePage(new HomeView());
    },

    page1:function () {
        this.changePage(new Page1View());       
    },   

    changePage:function (page, argumentos) {
        if (this.currentPage)
            this.currentPage.close();
        this.currentPage = page;
        $(page.el).attr('data-role', 'page');
        var render = page.render();

        $('body').append($(page.el));
        var transition = 'slide';      
        var reverse = false;
        if(argumentos && argumentos[0] == 'true'){
            reverse = true;
        }
        $.mobile.changePage($(page.el), {transition: transition, reverse: reverse});                 
    }
});

$(document).ready(function () { 
    Handlebars.registerPartial("header", $("#header-partial").html());
    Handlebars.registerPartial("footer", $("#footer-partial").html());
    var app = new AppRouter();
    Backbone.history.start();
    Backbone.history.navigate('home', {trigger: true});
    Backbone.View.prototype.close = function() {            
        this.unbind();
        this.remove();
    }      
});

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});
    }
});

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节点计数会表现出以下行为(内存下降的图形部分是我点击以强制进行垃圾收集的部分):

DOM node count increasing

我是这些技术的初学者,所以我想我做错了什么。我已经搜索过这个问题的答案了,但我发现我已经完成了所有事情(为每个被销毁的视图调用remove()和unbind())。

那么,我该如何处置这些节点?

2 个答案:

答案 0 :(得分:0)

我猜你还没有删除$ .mobile.changePage上的引用。

  $.mobile.changePage($(page.el), {transition: transition, reverse: reverse});

但是,我不熟悉jquery-mobile。但是我对backbonejs代码有一些评论。

我的建议是在index.html上添加一个DIV元素,它充当你的应用程序的视口。然后,您可以在此DIV上绑定所有视图对象。

的index.html

<div id="myviewport"></div>

HomeView.js

var HomeView = {
....
initialize: function () {
    this.$el = $("#myviewport");
},
....
};

你也可以做类似的渲染

//main.js
//since page.render() return this, you can chain them up
//In other 
$("body").append(page.render().$el);

答案 1 :(得分:0)

 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 }); 
                    }
};

undelegateEvents是取消定位所有事件的主要方法 Backbone.Validation.unbind(本);取消绑定骨干验证