闪烁的骨干视图 - 渲染方法的回调?

时间:2015-06-25 23:06:02

标签: javascript jquery backbone.js

我遇到的问题是我的父视图的render()方法在其子render()方法完成之前返回。

所以我在Backbone路由器中进行了这些调用:

       this.viewState.get('headerView').render();
       this.viewState.get('mainView').render();
       this.viewState.get('footerView').render(); //this function starts (and completes) before the above completes

问题是在mainView呈现之前页脚呈现,因为主视图render()函数在mainView的子视图完成呈现到DOM之前完全返回。因此,当页脚插入DOM时屏幕会闪烁,然后当mainView实际渲染时页脚会被按下。

我喜欢在Backbone视图的render()函数中使用“return this”的范例,但我能想到解决这个问题的唯一方法是使用异步库或其他东西链接render()函数,使用异步/ CPS回调。

所以,我将这段代码作为Backbone View的渲染函数的一部分:

//这里父母呈现它的子视图:

  function renderChildren($template) {
                    var ret = EJS.render($template, {
                        users: data
                    });

                    this.$el.html(ret); //***

                    this.childLoginView = new LoginView({el: this.$('#child-view-login-container')});
                    //console.log('this.childLoginView.$el', self.childLoginView.$el);
                    this.childLoginView.render();
                    this.childLoginView.delegateEvents();

                    this.childRegisteredUsersView = new RegisteredUsersView({el: this.$('#child-view-registered-users-container')});
                    //console.log('this.childRegisteredUsersView.$el', self.childRegisteredUsersView.$el);
                    this.childRegisteredUsersView.render();
                    this.childRegisteredUsersView.delegateEvents();

                    console.log('IndexView rendered');
                }

我可以告诉你一个事实,即在子视图实际渲染之前记录了“IndexView rendered”。这当然意味着子渲染函数是异步的,这也意味着只有在父视图的渲染方法完成后才渲染子视图,网页才会闪烁。

就像我说的,这表明render()方法确实是异步的。所以我想一次渲染一个视图,这样页面就不会闪烁 - 这是一个合理的想法吗?希望Web视图上的闪烁更少,因为事情只是连续呈现,但我不知道如何做到这一点。

关于***的行。有没有办法为父视图定义模板,并且只有在子视图渲染之后,才能使用.html()将模板插入到DOM中?这可能需要回调,在这种情况下,不可能从父视图的render()函数中“返回”。

1 个答案:

答案 0 :(得分:1)

您的view.render()中可能有一些异步操作导致竞争条件。

使用$.Deferred();

render: function () {
    var self = this,
        dfd = $.Deferred();
    this.model.fetch({
        succcess: function (response) {
          // do here the operations on your cached DOM:
          self.$el.append(response.model.models);
          dfd.resolve({template: self.$el});
        }
    });
    return dfd.promise();
}

现在您可以控制渲染方法的顺序:

$.when(viewState.get('headerView').render()).then(function(result) {
    $('body').append(result.template);
    viewState.get('mainView').render().then(function (result) {
        $('body').append(result.template);
    });
});

这将一次渲染一件。当承诺得到解决时,用户将看到屏幕的新部分出现。

看到这个小提琴:https://jsfiddle.net/h0h888rm/2/

如果你想等到每个渲染完成并只重新加载一次parentView,那么请考虑这个替代解决方案:

替代解决方案:

如果您希望渲染器以异步方式运行,但仅在完成所有渲染时才执行parentView渲染,请执行以下操作:

$.when(
    viewState.get('headerView').render(),
    viewState.get('mainView').render()
).then(function (result1, result2) {
    $('body').append(result1.template)
             .append(result2.template);
});

小提琴:https://jsfiddle.net/szLcfbne/