2012-11-05 48 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攔截器,以防止人們在工作時點擊事物。