How would I have the h1 change for each iteration of the loop? This code now only displays the h1 text after everything is done.
for (i=0; i<array.length; i++) {
$("body > h1").text("Processing #" + i);
// things that take a while to do
}
Additional info: if I resize the window as it loops, the html updates.
How would I have the h1 change for each iteration of the loop? This code now only displays the h1 text after everything is done.
for (i=0; i<array.length; i++) {
$("body > h1").text("Processing #" + i);
// things that take a while to do
}
Additional info: if I resize the window as it loops, the html updates.
Share Improve this question edited Feb 27, 2013 at 22:33 user1413341 asked Feb 27, 2013 at 22:16 user1413341user1413341 2261 gold badge4 silver badges18 bronze badges 3- the browser will not render until you yield control back to it. Which means it will not render until you get out of your for loop. But usually there are tricks to force it to re-render. Though I really remend you rewrite your loop to yield to the browser each iteration and continue afterwards...so the window does not lock up on the user. – Brandon Commented Feb 27, 2013 at 22:23
- 1 "Though I really remend you rewrite your loop to yield to the browser each iteration and continue afterwards" How do I do that? Thanks. – user1413341 Commented Feb 27, 2013 at 22:28
- I added an example to my answer. – Brandon Commented Feb 27, 2013 at 22:39
5 Answers
Reset to default 7var array = ['one', 'two', 'three']
var i = 0;
var refreshIntervalId = setInterval(function() {
length = array.length;
if (i < (array.length +1)) {
$("h1").text("Processing #" + i);
} else {
clearInterval(refreshIntervalId);
}
i++
}, 1000);
http://jsfiddle/3fj9E/
Use a setInterval
with a one-millisecond delay:
var i=0, j=array.length;
var iv = setInterval(function() {
$("h1").text("Processing #" + i);
// things that take a while to do
if (++i>=j) clearInterval(iv);
}, 1);
http://jsfiddle/mblase75/sP9p7/
Sometimes you can force a render by forcing a recalculation of layout
for (i=0; i<array.length; i++) {
$("body > h1").text("Processing #" + i)
.width(); // force browser to recalculate layout
// things that take a while to do
}
It might not work in all browsers.
A better way, that does not block the browser so much:
function doThings(array) {
var queueWork,
i = -1,
work = function () {
// do work for array[i]
// ...
queueWork();
};
queueWork = function () {
if (++i < array.length) {
$("body > h1").text("Processing #" + i);
setTimeout(work, 0); // yield to browser
}
};
}
doThings(yourArray);
DEMO
I've spent a bit of time working out a jquery function that seems to solve this. Basically, it's a process handler that you can add
any number of processes to and then call run
to sequentially call these in a asynchronous way.
$.fn.LongProcess = function () {
var _this = this;
this.notifications = [];
this.actions = [];
this.add = function (_notification, _action) {
this.notifications.push(_notification);
this.actions.push(_action);
};
this.run = function () {
if (!_this.actions && !_this.notifications) {
return "Empty";
}
//******************************************************************
//This section makes the actions lag one step behind the notifications.
var notification = null;
if (_this.notifications.length > 0) notification = _this.notifications.shift();
var action = null;
if ((_this.actions.length >= _this.notifications.length + 2) || (_this.actions.length > 0 && _this.notifications.length == 0))
action = _this.actions.shift();
//****************************************************************
if (!action && !notification) {
return "Completed";
}
if (action) action();
if (notification) notification();
setTimeout(_this.run, 1000);
//setTimeout(_this.run,1); //set to 1 after you've entered your actual long running process. The 1000 is there to just show the delay.
}
return this;
};
How to use with <h1 class="processStatus"></h1>
:
$(function () {
var process = $().LongProcess();
//process.add(notification function, action function);
process.add(function () {
$(".processStatus").text("process1");
}, function () {
//..long process stuff
alert("long process 1");
});
process.add(function () {
$(".processStatus").text("process2");
}, function () {
//..long process stuff
alert("long process 2");
});
process.add(function () {
$(".processStatus").text("process3");
}, function () {
//..long process stuff
alert("long process 3");
});
process.run();
});
if the process is very long you can use this script which shows every notification for a specific time interval.
here is the code..
html
<div id="ccNotificationBox"></div>
css
#ccNotificationBox{
-webkit-animation-name:;
-webkit-animation-duration:2s;/*Notification duration*/
box-sizing:border-box;
border-radius:16px;
padding:16px;
background-color:rgba(0,0,0,0.7);
top:-100%;
right:16px;
position:fixed;
color:#fff;
}
#ccNotificationBox.active{
-webkit-animation-name:note;
top:16px;
}
@-webkit-keyframes note{
0% {opacity:0;}
20% {opacity:1;}
80% {opacity:1;}
100% {opacity:0;}
}
javascript
var coccoNotification=(function(){
var
nA=[],
nB,
rdy=true;
function nP(a){
nA.push(a);
!rdy||(nR(),rdy=false);
}
function nR(){
nB.innerHTML=nA[0];console.log(nA[0]);
nB.offsetWidth=nB.offsetWidth;//reflow ios
nB.classList.add('active');
}
function nC(){
nB.classList.remove('active');
nB.innerHTML='';
nA.shift();
nA.length>0?nR():(rdy=true);
}
function init(){
nB=document.getElementById('ccNotificationBox');
nB.addEventListener('webkitAnimationEnd',nC,false);
window.removeEventListener('load',init,false);
}
window.addEventListener('load',init,false);
return nP
})();
usage
coccoNotification('notification 1');
example
http://jsfiddle/f6dkE/1/
info
the example above is perfect for external js as you use just one global variable which is the name of the function ... in my case coccoNotification
here is a different approach but it does the same
http://jsfiddle/ZXL4q/11/