简体   繁体   English

在Backbone Collection上迭代时更新DOM?

[英]Update DOM while iterating over Backbone Collection?

So I am trying to display a loading bar when rendering very large collections. 因此,我在渲染非常大的集合时尝试显示加载栏。 I have a placeholder for the loading bar when the page initially loads, and I am trying to update it like this: 当页面最初加载时,我有一个占位符用于加载栏,我试图像这样更新它:

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

The problem here is that the DOM isnt updated until the addAll function completes. 这里的问题是DOM没有更新,直到addAll函数完成。 I have a feeling that this is me not understanding some basic JS fundamentals. 我有一种感觉,这是我不理解一些基本的JS基础知识。 Any help would be greatly appreciated! 任何帮助将不胜感激!

Yes, you are missing something fundamental: the browser won't do any of its own work until your code returns control to the browser. 是的,你缺少一些基本的东西:在你的代码将控制权返回给浏览器之前,浏览器不会做任何自己的工作。

Consider some code like this: 考虑一下这样的代码:

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')

You'll see a brief pause and then #bar and #n will be updated and done will appear in the console. 您将看到一个短暂的暂停,然后#bar#n将更新并done将显示在控制台中。 Demo: http://jsfiddle.net/ambiguous/f5qKV/ (you might need to increase the 1000 to make things more obvious). 演示: http//jsfiddle.net/ambiguous/f5qKV/ (您可能需要增加1000以使事情变得更加明显)。

However, if you return control to the browser with setTimeout(..., 0) on each iteration: 但是,如果在每次迭代时使用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)

you'll be able to see #bar and #n changing and then you'll see done in the console when everything has finished. 你就可以看到#bar#n变化,然后你就会看到done在控制台时,一切都已经结束了。 Demo: http://jsfiddle.net/ambiguous/UCbY8/1/ 演示: http//jsfiddle.net/ambiguous/UCbY8/1/

Note that the setTimeout version uses the setTimeout callback to trigger the next timeout, that ensures that everything happens in the same order as they would in a simple for or each loop. 请注意, setTimeout版本使用setTimeout回调来触发下一个超时,这可确保所有操作的顺序与在简单foreach循环中的顺序相同。

The lesson is that you have to add some old-school pseudo cooperative multi-tasking hacks into the mix if you want to use that kind of progress indicator. 我们的教训是,如果你想使用那种进度指示器,你必须在混合中加入一些老式的伪合作多任务黑客。


Handing control back to the browser also leaves you open to user interaction when you're not expecting it. 将控制权交还给浏览器也会让您在不期望的情况下对用户交互开放。 You might want to add a general UI blocker to keep people from clicking on things while you're working if you go this route. 您可能希望添加一个通用的UI阻止程序,以防止人们在您工作时点击这些内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM