在Backbone Collection上迭代时更新DOM?

时间:2012-11-05 17:04:06

标签: javascript backbone.js coffeescript

所以我在渲染非常大的集合时尝试显示加载栏。当页面最初加载时,我有一个占位符用于加载栏,我试图像这样更新它:

addAll: 
  @collection.each(((obj, index) ->
    @addOne(obj, index)), this
  )

addOne: (obj, index) ->
  percent_complete = ((index / @collection.length) * 100)
  $(".loading_bar").width("#{percent_complete}%")
  # Proceed with rendering, create the view, etc

这里的问题是在addAll函数完成之前,DOM不会更新。我有一种感觉,这是我不理解一些基本的JS基础知识。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:3)

是的,你遗漏了一些基本的东西:在你的代码将控制权返回给浏览器之前,浏览器不会做任何自己的工作。

考虑一下这样的代码:

collection = [1..1000]

addOne = (index) ->
  $('#n').text(index + 1)
  percent_complete = ((index + 1) / collection.length) * 100
  $("#bar").width("#{percent_complete}%")

addOne(i) for e,i in collection  
console.log('done')

您会看到暂停,然后#bar#n将会更新,done将出现在控制台中。演示:http://jsfiddle.net/ambiguous/f5qKV/(您可能需要增加1000以使事情变得更加明显)。

但是,如果在每次迭代时使用setTimeout(..., 0)将控制权返回给浏览器:

collection = [1..1000]

addOne = (index) ->
  $('#n').text(index + 1)
  percent_complete = ((index + 1) / collection.length) * 100
  $("#bar").width("#{percent_complete}%")

i = 0
timeOut = ->
    if(i == collection.length)
        console.log('done')
        return
    addOne(i++)
    setTimeout(timeOut, 0)
setTimeout(timeOut, 0)

您将能够看到#bar#n更改,然后当一切都完成后,您将在控制台中看到done。演示:http://jsfiddle.net/ambiguous/UCbY8/1/

请注意,setTimeout版本使用setTimeout回调来触发下一次超时,这可以确保所有操作的顺序与简单for或{{1}中的顺序相同循环。

如果您想使用这种进度指示器,那么您必须在混音中添加一些旧式伪合作多任务黑客。


将控制权交还给浏览器也会让您在不期望的时候对用户进行交互。你可能想要添加一个通用的UI阻止程序,以防止人们在你工作的时候点击这些东西。