$.each not updating css width - javascript

So I have a loop, which performs an ajax call on each iteration and I want to set the progress bar updated.. But it is not updating, it goes to 100% directly when ending...
I've tried to put the bar update call outside the success action (inside the loop directly) but it isn't working either..
$('button.page').on('click', function(e){
var $userList = textArray($('#page-userlist').val().replace('http://lop/', '').split(/\n/));
var $proxyList = textArray($('#page-proxylist').val().replace('http://', '').split(/\n/));
var $question = $('#page-question').val();
var data = {
question: $question,
users: $userList,
proxies: $proxyList
};
var i = 0, p = 0, max = data.proxies.length, totalusers = data.users.length, percent = 0;
$('#log').append("\n" + moment().calendar() + "\n");
var progressbar = $('#page-progress');
$.each(data.users, function(k, u){
if(typeof(p) !== 'undefined' && p !== null && p > 0)
{
if(i % 10 == 0 && i > 1) p++;
if(p == max) return false;
}
var proxy = data.proxies[p];
percent = Math.round((i / totalusers) * 100);
$.ajax({
type: "POST",
url: Routing.generate('viral_admin_bot_page'),
data: {question: $question, user: u, proxy: proxy},
success: function(result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
},
error: function(error) {
$('#log').append(error);
}
});
i++;
});
});
If i do console.log(percent); it is updating perfectly on each iteration, so I don't know where can be the problem.
Here is my code (without the ajax call because it isn't the problem) http://jsfiddle.net/dvo1dm03/20/
it will output to console the percentage, the objetive is to update the bar to the percentage completed in each loop, so it goes in "realtime" with loop.

Ok, here's how to do it asynchrounously.
var speed = 75;
var number_of_calls_returned = 0; // add number_of_calls_returned++ in your ajax success function
var number_of_total_calls;
var loaded = false;
function processUserData(){
if( number_of_calls_returned < number_of_total_calls){
setTimeout(function(){processUserData();}, 200);
}
else{
//received all data
// set progressbar to 100% width
loaded = true;
$("#page-progress").animate({width: "100%"},500);
$("#page-proxylist").val("Received data");
}
}
function updateProgress(percent, obj){
setTimeout(function(x){
if(!loaded)
$(obj).width(x + "%");
}, percent*speed, percent);
}
$('button.page').on('click', function (e) {
var $userList = textArray($('#page-userlist').val().replace('http://lop/', '').split(/\n/));
var $proxyList = textArray($('#page-proxylist').val().replace('http://', '').split(/\n/));
var $question = $('#page-question').val();
var data = {
question: $question,
users: $userList,
proxies: $proxyList
};
var i = 0,
p = 0,
max = data.proxies.length,
totalusers = data.users.length,
percent = 0;
//$('#log').append("\n" + moment().calendar() + "\n");
var progressbar = $('#page-progress');
number_of_total_calls = totalusers;
$.each(data.users, function (k, u) {
if (typeof (p) !== 'undefined' && p !== null && p > 0) {
if (i % 10 == 0 && i > 1) p++;
if (p == max) return false;
}
var proxy = data.proxies[p];
percent = (i / totalusers) * 100; //much smoother if not int
updateProgress(percent, progressbar);
i++;
// simulate ajax call
setTimeout(function(){number_of_calls_returned++;}, Math.random()*2000);
});
//callback function
setTimeout(function(){processUserData();}, 200);
});
var textArray = function (lines) {
var texts = []
for (var i = 0; i < lines.length; i++) {
// only push this line if it contains a non whitespace character.
if (/\S/.test(lines[i])) {
texts.push($.trim(lines[i]));
}
}
return texts;
}
Check it out here! jsFiddle (really cool!)

Your problem is cause by the fact that you have a closure for your success function and every success function shares the same percent variable. You can fix it like this:
success: function(percent, result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
}.bind(percent),
Where you'll need to shim bind in older browsers, or like this, which is a little uglier, but should work everywhere without a shim:
success: (function(percent) { return function(result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
}; }( percent ),

if what you want is to increase the update bar with each success of AJAX calls I'd suggest an easier solution (I've simplified the js code for clarity's sake):
$('button').click(function (e) {
var i = 0,
cont = 0,
totalusers = 100,
percent = 0;
var progressbar = $('#page-progress');
for (; i < totalusers; i++) {
$.ajax({
type: "POST",
url: '/echo/json/',
data: {
question: 'something',
user: 1,
proxy: 2
},
success: function (result) {
cont += 1;
percent = Math.round((cont / totalusers) * 100);
progressbar.width(percent + "%");
},
error: function (error) {
$('#log').append(error);
}
});
};
});
You can see it in action in this fiddle.
Hope this helps or at least give you some ideas.

Update the progress bar using setTimeout method.
it will wait for some time and then update the width of progressbar.
myVar = setTimeout("javascript function",milliseconds);
Thanks,
Ganesh Shirsat

I would like to make a recommendation of trying to make a self contained example that doesn't rely on the post so that it is easier for you or us to solve the problem
As well, you can console log elements so you could try logging the progressbar element, percent and the response of the ajax request
(This code is to replace the javascript sections of the fiddler)
var i = 0;
moveProgress();
function moveProgress(){
if(i < 10000)
{
setTimeout(function(){
$('#page-progress').width((i / 1000) * 100);
moveProgress();
},2);
i++;
}
}
The reason that it wasn't working was because the loop ran so fast that it was loaded by the time the script loaded it, the timeout allows you to delay the execution a bit(Though not necessarily recommended to use because of potential threading issues.

Related

Add a delay between ajax get requests

I have a script that makes an ajax GET request once the user gets near the bottom of the page.
$(function(){
window.addEventListener('scroll', fetchImages);
window.addEventListener('scroll', fetchNotifications);
});
function fetchImages() {
var imagePage = $('.endless-pagination').data('next-page');
if(imagePage !== null) {
var last = $('.endless-pagination').data('last-item');
var within = $('.endless-pagination').data('within');
var orderBy = $('.endless-pagination').data('order-by');
clearTimeout( $.data( this, "scrollCheckImages" ) );
$.data( this, "scrollCheckImages", setTimeout(function() {
var scroll_position_for_images_load = $(window).height() + $(window).scrollTop() + 900;
if(scroll_position_for_images_load >= $(document).height()) {
$(".dual-ring-container").show();
$.ajax({
url: imagePage,
method: 'get',
cache: false,
})
.done(function( data ) {
if (last != null) {
$(".dual-ring-container").hide();
var newPageUrl = data.next_page + "&within=" + within + "&orderBy=" + orderBy + "&last=" + last;
$('.endless-pagination').append(data.images);
$('.endless-pagination').data('next-page', newPageUrl);
setResizeVariables();
updateReadMore();
initMentions();
}
});
}
}, 350))
}
}
However, there's a bit of a problem. This get request is essentially being spammed since the function is being triggered by a "scroll" event listener.
How could I make it so that this request can only be called once every few seconds or so?
Use a variable that keeps track of the last time the main body of the function was run, and return early if it was run less than a few seconds ago:
let lastCall = 0;
function fetchImages() {
const now = Date.now();
if (now - lastCall < 3000) return;
lastCall = now;
// ...
Note that you can use a similar strategy to reduce unnecessary indentation hell. Rather than
if (imagePage !== null) {
// big block of code
}
} // end of fetchImages
you can use
if (imagePage === null) return;
which will have the exact same effect, but will make your code a bit more readable.

Ajax succes in loop to set global variable

I want to set global variable from function and loop ajax to get distance.
However the nearestIndex variable is always undefined.
First solution I got was to use async: false - this is work in my pc browser, but this project is webservice to android, and this solution not work to webview.
And of course async: false not recommended. I need this example in my case, I've been looking for this problem in stack overflow, but i always failed to understand about callback.
var allDestination = ["A", "B", "C"];
var nearestIndex;
function getNearest(){
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var tempDistance;
for(var i=0; i<allDestination.length; i++){
var destination = allDestination[i].getLatLng().lat + "," + allDestination[i].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function (data) {
var distance = data.distance;
if(i == 0){
tempDistance = distance;
nearestIndex = i;
} else {
if(distance < tempDistance){
tempDistance = distance;
nearestIndex = i;
}
}
}
});
}
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
getNearest();
allDestination[nearestIndex].addTo(map);
}
As you are dealing with Async call; your relevant code has to get called from success handler of ajax call as follows:
var allDestination = ["A", "B", "C"];
var nearestIndex;
var tempDistance;
var successReceived = 0; //counter to keep watch on ajax success callback
//modify the function signature to receive index as well as callback function
function getNearest(index, callbackFunction) {
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var destination = allDestination[index].getLatLng().lat + "," + allDestination[index].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function(data) {
successReceived++; //increment the success counter
var distance = data.distance;
if (index == 0) {
tempDistance = distance;
nearestIndex = index;
} else {
if (distance < tempDistance) {
tempDistance = distance;
nearestIndex = index;
}
}
//check if we got all the ajax response back. If yes then call the callback function
if(successReceived == allDestination.length && typeof callbackFunction == 'function')
{
callbackFunction();
}
}
});
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
for (var i = 0; i < allDestination.length; i++) {
//pass the current index and callback function
getNearest(i,function(){
allDestination[nearestIndex].addTo(map);
});
}
}
I ever have got the same problem like you,
it because asincrounous function cant return anything.
so I think you shoud inject allDestination[nearstIndex].addTo(map); into ajax success
if(i == 0){
tempDistance = distance;
allDestination[i].addTo(map);
} else {
if(distance < tempDistance){
tempDistance = distance;
allDestination[i].addTo(map);
}
}
or you create function to handle ajax success,,, CMIIW

Ajax call doesn't work after success

I have a problem with ajax call after success.
I am trying to call my following javascript codes:
function imgResize($, sr) {
var debounce = function(func, threshold, execAsap) {
var timeout;
return function debounced() {
var obj = this,
args = arguments;
function delayed() {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function(fn) {
return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr);
};
};
//CALL ON PAGE LOAD OR ANY TIME YOU WANT TO USE IT
imgResize(jQuery, 'smartresize');
/* Wait for DOM to be ready */
// Detect resize event
$(window).smartresize(function() {
// Set photo image size
$('.photo-row').each(function() {
var $pi = $(this).find('.photo-item'),
cWidth = $(this).parent('.photo').width();
// Generate array containing all image aspect ratios
var ratios = $pi.map(function() {
return $(this).find('img').data('org-width') / $(this).find('img').data('org-height');
}).get();
// Get sum of widths
var sumRatios = 0,
sumMargins = 0,
minRatio = Math.min.apply(Math, ratios);
for (var i = 0; i < $pi.length; i++) {
sumRatios += ratios[i] / minRatio;
};
$pi.each(function() {
sumMargins += parseInt($(this).css('margin-left')) + parseInt($(this).css('margin-right'));
});
// Calculate dimensions
$pi.each(function(i) {
var minWidth = (cWidth - sumMargins) / sumRatios;
$(this).find('img')
.height(Math.floor(minWidth / minRatio))
.width(Math.floor(minWidth / minRatio) * ratios[i]);
});
});
});
/* Wait for images to be loaded */
$(window).load(function() {
$(".photo").each(function() {
var imgGrab = $(this).find('.photo-item');
var imgLength = imgGrab.length;
for (i = 0; i < imgLength; i = i + 3) {
imgGrab.eq(i + 1)
.add(imgGrab.eq(i + 1))
.add(imgGrab.eq(i + 2))
.wrapAll('<div class="photo-row"></div>');
}
$(this).find(".photo-item").each(function() {
if ($(this).parent().is(":not(.photo-row)")) {
$(this).wrap('<div class="photo-row"></div>');
}
});
// Store original image dimensions
$(this).find('.photo-item img').each(function() {
$(this)
.data('org-width', $(this)[0].naturalWidth)
.data('org-height', $(this)[0].naturalHeight);
});
});
$(window).resize();
});
And here is my ajax code for LOAD MORE POST
$('body').on("click",'.morep', function(event) {
event.preventDefault();
var ID = $(this).attr("id");
var P_ID = $(this).attr("rel");
var URL = $.base_url + 'more_post.php';
var dataString = "lastpid=" + ID + "&post_id=" + P_ID;
if (ID) {
$.ajax({
type: "POST",
url: URL,
data: dataString,
cache: false,
beforeSend: function() {
$("#more" + ID).html('<img src="loaders/ajaxloader.gif" />');
},
success: function(html) {
$("div.post-content").append(html);
$("#more" + ID).remove();
imgResize(jQuery, 'smartresize');
}
});
} else {
$("#more").html('FINISHED');
}
return false;
});
The ajax should call imgResize(jQuery, 'smartresize'); but it is not working. What I am missing here anyone can help me here ?

Update progressbar in each loop

I have a progress bar that I update in a loop of many iterations.
https://jsfiddle.net/k29qy0do/32/
(open the console before you click the start button)
var progressbar = {};
$(function () {
progressbar = {
/** initial progress */
progress: 0,
/** maximum width of progressbar */
progress_max: 0,
/** The inner element of the progressbar (filled box). */
$progress_bar: $('#progressbar'),
/** Set the progressbar */
set: function (num) {
if (this.progress_max && num) {
this.progress = num / this.progress_max * 100;
console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max);
this.$progress_bar.width(String(this.progress) + '%');
}
},
fn_wrap: function (num) {
setTimeout(function() {
this.set(num);
}, 0);
}
};
});
$('#start_button').on('click', function () {
var iterations = 1000000000;
progressbar.progress_max = iterations;
var loop = function () {
for (var i = 1; i <= iterations; i++) {
if (iterations % i === 100) {
progressbar.set(i); //only updates the progressbar in the last iteration
//progressbar.fn_wrap(i); //even worse, since no output to the console is produced
}
}
}
//setTimeout(loop, 0);
loop();
});
The console is updated iteratively as expected.
However, the progressbar is not updating.
The problem is that the browser window seems to 'hang' until the loop finishes.
Only the console is updated, not the progressbar.
I have tried to add the setTimeout, as suggested below, in several places.
But that just makes things worse, because I then do not even get the console to output the progress while executing the loop.
Okay, I found a solution in the answer to this question:
Javascript: How to update a progress bar in a 'for' loop
var i = 0;
(function loop() {
i++;
if (iterations % i === 100) {
progressbar.set(i); //updates the progressbar, even in loop
}
if (i < iterations) {
setTimeout(loop, 0);
}
})();
My solution:
https://jsfiddle.net/ccvs4rer/3/
Lets break this down to steps
Step 1: Clean up HTML
Assuming the purpose of your question is to understand how to work the progress bar and not the styles or the labels (loading, please be patient, etc.). Lets just have the progress bar and the start button.
<div id='progressbar-outer' style="">
<div id='progressbar' style=""></div>
</div>
<button id="start_button">Start</button>
Step 2: The Styles
Lets make the progress bar visible to the user
#progressbar-outer {
height:2em;
border:5px solid #000;
width:15em;
}
#progressbar {
width:0%;
background-color:#F00;
height:100%;
}
Step 3: Using setTimeout where it belongs
In your code, you have used setTimeout to set the value of your progress bar. However, the for loop is still active.
for (var i = 1; i <= iterations; i++) {
if (iterations % i === 100) {
progressbar.set(i); //only updates the progressbar in the last iteration
//progressbar.fn_wrap(i); //even worse, since no output to the console is produced
//setTimeout(function() {
// progressbar.set(i);
//}, 0);
}
}
The use of setTimeout does not affect the rest of the code. Hence, the UI was held hostage till the loop ended. Try the following code.
$('#start_button').on('click', function () {
var iterations = 100;
progressbar.progress_max = iterations;
var loop = function (value) {
progressbar.set(value);
if (value < iterations) setTimeout(function () {
loop(value + 1)
}, 30);
else $('#progressbar').css('background-color', '#0F0');
}
loop(1);
});
Preview
Try this fiddle: https://jsfiddle.net/Ljc3b6rn/4/
What you really want is an Asynchronous loop to allow the browser to update the DOM in between iterations.
JSFiddle: http://jsfiddle.net/u5b6gr1w/
function delayedLoop(collection, delay, callback, context) {
context = context || null;
var i = 0,
nextInteration = function() {
if (i === collection.length) {
return;
}
callback.call(context, collection[i], i);
i++;
setTimeout(nextInteration, delay);
};
nextInteration();
}
Some HTML:
<div class="progress-bar"><div style="width: 0"></div></div>
A splash of CSS:
.progress-bar {
border: 1px solid black;
background-color: #f0f0f0;
}
.progress-bar div {
background-color: red;
height: 1.25em;
}
And some JavaScript to wire things together:
var progressBar = document.querySelector(".progress-bar div"),
items = [1,2,3,4,5,6,7,8,9,10];
delayedLoop(items, 500, function(item, index) {
var width = (item / items.length * 100) + "%";
progressBar.style.width = width;
progressBar.innerHTML = width;
});
My guess would be that all your progress updates are running in the same call stack. While JavaScript code is running, the DOM cannot update. Maybe this question will help you come up with a work-around.
What do you wnat to do? Why do you need it? You should only use a progressbar when you have to wait for something to finish. But we don't know what you do on your page.
If you want to display the progress of an ajax upload:
$.ajax({
...
xhr: function() {
var xhr = $.ajaxSettings.xhr();
$(xhr.upload).bind("progress", function(event) {
var e = event.originalEvent;
var percent = 0;
if (e.lengthComputable)
percent = Math.ceil(e.loaded/e.total*100);
$("#progress").width(percent+"%");
});
return xhr;
}
...
});
For images, you need an ajax call:
$.ajax({
method: "GET",
url: "http://example.com/path/image.jpg",
xhr: function() {/* see the code above*/ }
...
});
For getting the content of an uploaded file:
var reader = new FileReader();
reader.readAsText(uploadedFile);
$(reader).bind("progress", function(e) {
var percent = 0;
if (e.lengthComputable)
percent = Math.ceil(e.loaded/e.total*100);
$("#progress").css("width", percent+"%");
});
For large around of process, like math or appending a lot of divs that will take 10+ secons:
Main.js:
var worker = new Worker("Worker.js");
$(worker).bind("message", function(data) {
$("#progress").width((data*100)+"%");
});
Worker.js:
var total = 43483,
finished = 0,
doStuff = function() {
++finished;
return 1+1;
};
setInterval(function()
{
self.postMessage(finished/total);
}, 100);
for (var i = 0; i < total; ++i)
setTimeout(doStuff, i*10);
Because it's nice, and you want to tell the user there's a progress when there isn't, just animate the div:
$("#progress").animate({width: "100%"}, 3000);
You can use promises to wait until the width is set before continuing the loop.
Updating the progress bar for 1000000000 iterations will be slow if you go 1 by 1, so you might find it useful to decrease the update frequency.
Instead of a for loop, I used a recursive function that loops when the promise has been fulfilled.
set: function (num) {
var deferred = $.Deferred();
if (this.progress_max && num) {
this.progress = num / this.progress_max * 100;
var self = this;
self.$progress_bar.animate({"width": String(this.progress) + '%'}, "fast", function() {
deferred.resolve();
});
return deferred;
}
}
$('#start_button').on('click', function () {
var iterations = 1000000000;
var i = 0;
progressbar.progress_max = iterations;
var loop = function(){
i+=100000000;
if(i <= iterations){
progressbar.set(i).then(function(){
loop();
}); ;
}
};
loop();
});
https://jsfiddle.net/k29qy0do/34/
You have to use window.requestAnimationFrame, otherwise the browser will block until your loop is finished. The callback passed to requestAnimationFrame will get a timestamp as a parameter which you might be able to use for calculations of the progress.
This are my 2 takes on the question:
Using a web worker. The webworker blob code comes from here
Web worker code:
<script type="text/ww">
function loop(e) {
var data = JSON.parse(e.data);
var i = parseInt(data.i, 10);
var iterations = parseInt(data.iterations, 10);
while (iterations % ++i !== 100 && i <= iterations);
if(i <= iterations) {
self.postMessage(JSON.stringify({ i: i, iterations: iterations }));
}
}
self.onmessage = function(e) {
loop(e);
};
</script>
The code:
var ww = document.querySelector('script[type="text/ww"]'),
code = ww.textContent,
blob = new Blob([code], {type: 'text/javascript'}),
blobUrl = URL.createObjectURL(blob),
worker = new Worker(blobUrl);
worker.onmessage = function(e) {
var data = JSON.parse(e.data);
var i = parseInt(data.i, 10);
var iterations = parseInt(data.iterations, 10);
progressbar.set(i);
worker.postMessage(JSON.stringify({ i: i, iterations: iterations }));
}
$('#start_button').on('click', function () {
var iterations = 1000000000;
progressbar.progress_max = iterations;
worker.postMessage(JSON.stringify({ i: 0, iterations: iterations }));
});
The other idea hangs the UI thread, but changes the width visually, as I use requestAnimationFrame to break the counting, change width of the progressbar, and then continue the count.
function loopFrame(i, iterations) {
requestAnimationFrame(function() {
if (iterations % i === 100) {
progressbar.set(i);
}
if(i < iterations) {
loopFrame(i + 1, iterations);
}
});
}
$('#start_button').on('click', function () {
var iterations = 1000000000;
console.log(iterations);
progressbar.progress_max = iterations;
loopFrame(0, iterations);
});
Maybe this will be usefull.
var service = new Object();
//function with interrupt for show progress of operations
service.progressWhile = new Object();
service.progressWhile.dTime = 50; //step ms between callback display function
service.progressWhile.i = 0; //index
service.progressWhile.timer = 0; //start time for cycle
//#parametr arr - array for actions
//#parametr actionCallback - The function for processing array's elements
//#parametr progressCallback - function to display the array index
function progressWhile(arr, actionCallback, progressCallback) {
try {
var d = new Date();
service.progressWhile.timer = d.getTime();
log(service.progressWhile.i);
if (service.progressWhile.i >= arr.length) {
service.progressWhile.i = 0;
return;
}
while (service.progressWhile.i < arr.length) {
actionCallback(arr[service.progressWhile.i++]);
d = new Date();
if (d.getTime() - service.progressWhile.timer > service.progressWhile.dTime) {
break;
}
}
if (progressCallback != undefined)
progressCallback(service.progressWhile.i);
} catch (er) {
log(er);
return;
}
setTimeout(function () {
progressWhile(arr, actionCallback, progressCallback);
}, 0);
}
Here's updated fiddle
I used animate to make it a progress bar like look and feel.
Hope this will help you.
var progressbar = {};
$(function() {
progressbar = {
/** initial progress */
progress : 0,
/** maximum width of progressbar */
progress_max : 0,
/** The inner element of the progressbar (filled box). */
$progress_bar : $('#progressbar'),
/** Method to set the progressbar.*/
set : function(num) {
if (this.progress_max && num) {
this.progress = num / this.progress_max * 100;
console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max);
$('#progressbar').animate({
width : String(this.progress) + '%',
}, 500, function() {
// Animation complete.
});
}
},
fn_wrap : function(num) {
setTimeout(function() {
this.set(num);
}, 0);
}
};
});
$('#start_button').on('click', function() {
$('#progressbar').css('width', '0%');
var iterations = 1000000000;
progressbar.progress_max = iterations;
var loop = function() {
for (var i = 1; i <= iterations; i++) {
if (iterations % i === 100) {
progressbar.set(i);
//only updates the progressbar in the last iteration
}
}
}
loop();
});
Fiddler
[1]: https://jsfiddle.net/k29qy0do/21/

A for cycle can't wait

How can I force for cycle to wait for every XHR to be completed before it runs? I know a way which is in comment, but it kills real-time of percentage counter.
var data = new Array, per = 0;
WinJS.xhr({url : "http://index.hu/tech/rss"}).done(function(req){
$($.parseXML(req.response)).find("item title:lt(5)").each(function() {
data.push({
h : this.textContent
})
}).next().each(function(ind) {
WinJS.xhr({
url : this.textContent
}).done(function(req) {
per += 100 / 30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = req.response.match(/<p>(.+?)<\/p>/)[1]
})
/*var req = new XMLHttpRequest;
req.open("get", this.textContent, false);
req.onreadystatechange = function()
{
if(this.readyState == 4)
{
per += 100/30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = this.response.match(/<p>(.+?)<\/p>/)[1]
}
}
req.send()*/
})
for(var ind in data)
{
//console.log(data[ind].p)
}
})
Instead of using a for loop for that, you could attach a callback function on the XHR request that checks if the stopping condition of the for loop is met, and then stops, or else makes the requisition one more time.
You can just wait using setTimeout. See line setTimeOut(wheAllDone, 100); below:
var items = $($.parseXML(req.response)).find("item title:lt(5)").each(function()
{
data.push(
{
h : this.textContent
})
}).next();
var itemsCount = items.length;
var doneSoFarCount = 0;
items.each(function(ind)
{
WinJS.xhr(
{
url : this.textContent
}).done(function(req)
{
per += 100 / 30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = req.response.match(/<p>(.+?)<\/p>/)[1]
doneSoFarCount ++;
})
});
var wheAllDone = null;
wheAllDone = function() {
if(doneSoFarCount >= itemsCount)
{
for(var ind in data)
{
//console.log(data[ind].p)
}
} else {
setTimeOut(wheAllDone, 100); // <<<<< Wait a bit for all to complete
}
};

Categories