How to improve rendering performance when using $.html()

后端 未结 1 1073
长发绾君心
长发绾君心 2020-11-30 15:55

I am working on a Backbone demo app that shows a list of tweets. As I am replacing all the \"tweets\" with different data I clear the list using $.html()

<
相关标签:
1条回答
  • 2020-11-30 16:12

    Create a new DocumentFragment to pre-render all the items, then update the DOM once.

    Also, favor this.$(...) over the global jQuery selector $(...).

    this.$ is a proxy to this.$el.find(...) which is more efficient, and less prone to select something outside of the view.

    Using jQuery's core function ($()) inside a view can fail if the view wasn't rendered yet. So it's better to always manipulate through this.$el so you can make changes even before the view is actually put in the DOM.

    Keep all the sub views created in an array to cleanly remove them later.

    initialize: function() {
        this.childViews = [];
    },
    render: function() {
        // cache the list jQuery object
        this.$list = this.$("#item-table");
    
        // Make sure to destroy every child view explicitely 
        // to avoid memory leaks
        this.cleanup();
    
        this.renderCollection();
        return this;
    },
    

    The real optimization starts here, with a temporary container.

    renderCollection: function() {
        var container = document.createDocumentFragment();
    
        this.collection.each(function(model) {
            // this appends to a in memory document
            container.appendChild(this.renderItem(model, false).el);
        }, this);
    
        // Update the DOM only once every child view was rendered.
        this.$list.html(container);
        return this;
    },
    

    Our renderItem function can still be used to render a single item view and immediatly put it in the DOM. But it also provides an option to postpone the DOM manipulation and it just returns the view.

    renderItem: function(model, render) {
        var view = new Item({ model: model });
    
        this.childViews.push(view);
        view.render();
        if (render !== false) this.$list.append(view.el);
        return view;
    },
    

    To avoid memory leaks with dangling listeners, it's important to call remove on each view before forgetting about it.

    I use an additional optimization by deferring the actual call to remove so we don't waste time now while the user waits.

    cleanup: function() {
        var _childViewsDump = [].concat(this.childViews);
        this.childViews = [];
    
        while (_childViewsDump.length > 0) {
            var currentView = _childViewsDump.shift();
            // defer the removal as it's less important for now than rendering.
            _.defer(currentView.remove.bind(currentView), options);
        }
    }
    
    0 讨论(0)
提交回复
热议问题