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. I have a feeling that this is me not understanding some basic JS fundamentals. 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. Demo: http://jsfiddle.net/ambiguous/f5qKV/ (you might need to increase the 1000 to make things more obvious).
However, if you return control to the browser with setTimeout(..., 0)
on each iteration:
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. Demo: 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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.