添加模型时Ember.js闪烁列表内容 - 我该如何解决?

时间:2013-04-01 22:01:38

标签: pagination ember.js

我正在使用Ember.js构建一个应用程序,该应用程序使用Server-Sent Events添加和更新实现分页的控制器。下面列出了控制器的完整实现。

    App.endpointsDisponiblesClass = Ember.ArrayController.extend({
    loading: true,
    completeList:[
         /*
         App.Endpoint.create({
             id: 1,
             id_manufacturer: 1,
             id_model: 1,
             mac_address: '00:11:22:33:44:55',
             last_known_ipv4:   '10.0.0.1',
             last_scanned:      '2012-12-31',
             last_configured:   null
         }),
         */
    ],
    content:    [],
    offset: null,
    limit:  10,
    displaySlice: function(offset) {
        if (offset >= this.completeList.length)
            offset = this.completeList.length - 1;
        if (offset < 0) offset = 0;
        offset = offset - (offset % this.get('limit'));
        if (this.get('offset') == null || offset != this.offset) {
            var slice = this.completeList.slice(offset, offset + this.get('limit'));
            this.set('offset', offset);
            this.set('content', slice);             
        }
    },
    displayStart: function() { this.displaySlice(0); },
    displayPrevious: function() { this.displaySlice(this.offset - this.limit); },
    displayNext: function() { this.displaySlice(this.offset + this.limit); },
    displayEnd: function() { this.displaySlice(this.completeList.length); },
    startPosition: function() {
        return this.get('offset') + 1;
    }.property('offset'),
    endPosition: function() {
        var pos = this.get('offset') + this.get('limit');
        if (pos > this.completeList.length)
            pos = this.completeList.length;
        return pos;
    }.property('offset', 'limit'),
    displayRefresh: function() {
        console.debug('displayRefresh');
        var offset = this.get('offset');
        this.set('offset', null);
        this.displaySlice(offset);
    }.observes('completeList.@each')
});
App.endpointsDisponibles = App.endpointsDisponiblesClass.create();

completeList元素包含我要翻阅的元素的完整列表,其中一个列为注释。在我的实现中,我通过将完整列表的切片分配给ArrayController子类的'content'元素来执行分页。此外,还有一些辅助方法可以从显示Next,Back等按钮的各种视图中调用。

呈现模型列表的模板片段如下所示:

{{#view tagName="tbody"}}
{{#each App.endpointsDisponibles}}
<tr class="neo-table-data-row">
    <td class="neo-table-data-row">{{view Ember.Checkbox checkedBinding="isSelected"}}</td>
    <td class="neo-table-data-row">{{mac_address}}</td>
    <td class="neo-table-data-row"><a target="_blank" {{bindAttr href="adminUrl"}}>{{last_known_ipv4}}</a></td>
    <td class="neo-table-data-row">{{name_manufacturer}}</td>
    <td class="neo-table-data-row">{{view Ember.Select
        contentBinding="modelSelect"
        optionValuePath="content.id_model"
        optionLabelPath="content.name_model"
        valueBinding="id_model"
        disabledBinding="App.endpointScanController.scanInProgress"}}</td>
</tr>
{{else}}
<tr class="neo-table-data-row">
    <td class="neo-table-data-row" colspan="7">No endpoints have been discovered or loaded.</td>
</tr>
{{/each}}
{{/view}}

我准备一个带有onmessage处理程序的EventSource,该处理程序解析来自服务器的JSON消息,并通过在completeList上添加/更新/删除模型来更新completeList。由于我使用displayRefresh()观察completeList。@ each,因此在我查看最后一页并添加模型或者删除其中一个已查看模型的情况下,页面切片会更新。到目前为止,它完美无缺。

问题是消息触发插入的一半时间,用户非常清楚地重新呈现模板。模板被清空,在大约几分之一秒内保持空白,然后重新填充适当的内容。另一半时间,模板内容得到平滑更新,无需清空和重新填充,这就是我想要的。 SSE消息流是突发性的 - 它空闲几秒钟,然后在不到一秒的时间内触发大约5到6条消息,然后循环重复。在Firefox和谷歌浏览器中都观察到了丑陋的渲染。

在Firefox中,我安装了Firebug,我可以从控制台调用控制器方法。当我这样做时,它们的行为与SSE案例完全相同。有时刷新是平滑的,有时模板的清空和重新填充是可见的。

如何确保模板渲染始终如一?

1 个答案:

答案 0 :(得分:0)

我遇到了类似的问题 - 这个问题是谷歌搜索“arraycontroller flash”时出现的唯一结果。

当我重置阵列控制器的模型时会出现问题:

      @set 'model', message

有趣的是,我有一个几乎相同的应用程序,我使用淘汰赛构建 - 并且没有闪烁/刷新问题。

我偶然发现了这篇文章:Mitigating a flickering UI when refreshing content in Ember并最终将我的更新包装在Ember.run函数中,这解决了闪烁问题,但我似乎仍然不对。

      Ember.run =>
        @set 'model', message

[删除完整的红鲱鱼]

截至目前,似乎正确的路径是将Ember.run包裹起来 - 丑陋如同地狱,但它确实解决了眼前的问题。我的猜测是Ember并不像淘汰那样优化/快速,或者Ember有更新排队的错误。希望它会随着时间的推移而改善。

编辑7/23/13 -

在我写完之后我意识到Ember是完全正确的,我完全错了。 (而且淘汰赛是偶然的)

如下所述:http://emberjs.com/guides/understanding-ember/managing-asynchrony/似乎Ember使用事件将更新捆绑在一起 - 在Ember.run中有效地包装事件处理程序

但在我的情况下(我认为你的)我们正在调用一个异步的ajax方法。在Ember事件触发并返回后发生回调(或承诺 - 同样的问题)。所以Ember无法知道它需要排队更新。

仍然不确定“正确”的解决方案是将其包装在Ember.run中 - 文档(http://emberjs.com/api/classes/Ember.run.html)似乎表明它不对,但文档也推向了Ember Data,它不会有这个问题。

猜猜我需要再读一遍Ember的runloop。