2012-11-05 50 views
1

所以我想在渲染非常大的集合时显示加载栏。我对加载条的占位符当页面最初加载,和我想这样来更新它:在遍历Backbone集合时更新DOM?

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 

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

回答

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当一切都完了。演示:该setTimeout版本使用setTimeout回调触发下一个超时http://jsfiddle.net/ambiguous/UCbY8/1/

注意,确保一切都以相同的顺序发生,因为他们会在一个简单的foreach环。

如果您想使用这种进度指示器,您必须添加一些老式的伪协作式多任务黑客入门。


将控制交还给浏览器还会让您在不期待的时候向用户交互。如果你走这条路线,你可能想添加一个通用的UI拦截器,以防止人们在工作时点击事物。