As my loop is so fast, the intervals are overlapping and not able to stop one timerId. here is my code:
data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
Jbin
try {
var data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay);
}
function CallTheAPI(jobNumber) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
function startPolling() {
var pollStatus = '';
timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval ' + timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = " + jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### " + timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
Your timer_id variable is on the global scope and hence overwritten every time you call startPolling.
So when you'll call clearInterval(timer_id), timer_id will be the id of the last setInterval, and the first one will keep running endlessly.
Simply add a var in your startPolling function so that timer_id be scoped correctly, and that it doesn't get overwritten by next call.
try {var data = ['115536', '117202'];
var scan_delay = 500;
// remove this one
//var timerId;
var scannedItemsList = [];
var tableDataList = [];
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay) ;
}
function CallTheAPI(jobNumber) {
$.ajax({
url: "https://jsonplaceholder.typicode.com/todos/1",
type: "GET",
async: true,
success: function (response) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
});
}
function startPolling() {
var pollStatus = '';
/////////
///HERE
/////////
// Declare timerId in startPolling scope
/////////
var timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval '+ timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = "+ jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### "+ timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Related
So I get multiple objects from a REST API.
I get the data via AJAX like this:
var APICaller = (function () {
let endpoint = "https://jsonplaceholder.typicode.com/";
function api_call(method, url, data, callback) {
$.ajax({
url: url,
method: method,
data: data,
success: callback
});
}
function get_users(callback) {
let method = "GET";
let url = endpoint + "users";
let data = {};
api_call(method, url, data, callback);
}
return {
get_users: get_users,
};
})();
I am rolling 3 dices, and the total values of these 3 dices should be attached to each user so i can order the "scoreboard" after the total value.
I wonder if there is any way to attach the variable totalamount to every user?
Thanks in advace!
EDIT:
Currently i am getting all the users from the api.
This is the rest of my code withing this topic:
var Game = (function () {
var dice_total;
//Function for when the dice rolls.
function roll_dice() {
var value1 = $(".val1");
var value2 = $(".val2");
var value3 = $(".val3");
var v1 = Math.floor(Math.random() * 6) + 1;
var v2 = Math.floor(Math.random() * 6) + 1;
var v3 = Math.floor(Math.random() * 6) + 1;
value1.html(v1);
value2.html(v2);
value3.html(v3);
dice_total = v1 + v2 + v3;
}
return {
roll_dice: roll_dice
};
})();
var EventHandlers = (function () {
function init() {
var currentPlayer;
APICaller.get_users(on_get_users_success);
function on_get_users_success(response) {
//For each user in the API
$.each(response, function (i, user) {
$("#my-list").append('<li class="list-li"><a class="list-a">' + user.name + '</a></li>');
//Create the divs and p tags
$("#dice_value").append('<div class="val_div"> <p class="val1"></p> <p class="val2"></p> <p class="val3"></p></div>');
});
//change information
$("#info-txt").text("Välj en spelare!");
}
// On klick on a user make klicked user your own player.
$("#my-list").on('click', '.list-a', function () {
currentPlayer = this.text;
$("#info-txt").text("Tryck på spela knappen för att börja spelet!");
$("#currentPlayer-div").animate({
height: '300px',
opacity: '1'
});
$("#currentPlayer-h3").text(currentPlayer);
});
// On klick of the play button
$("#startGame-button").click(function () {
$().animate();
$("#currentPlayer-div").animate({
height: '150px'
});
$("#startGame-button").animate({
opacity: '0'
});
$("#dice_value").animate({
opacity: '1'
});
Game.roll_dice();
});
// $(".button-to-hide").click(function (){
// $(this).hide();
// });
// $("#show-all-buttons").click(function (){
// $(".button-to-hide").show();
// });
// $("#btn-edit-text").click(function (){
// var value = $("#my-input").val();
// $("p").html(value);
// });
}
return {
init: init,
}
})();
var DocumentEdit = (function () {
return {
}
})();
$(document).ready(function () {
EventHandlers.init();
});
Hope that describes it.
I want to prevent my function from re-executing for one second after it's last executed. I've tried the method below, but it doesn't work.
function displayOut() {
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
pause();
};
function pause() {
setTimeout(function() {
// Wait one second!
}, 1000);
}
You could use a pattern like this:
var executing = false;
function myFunc() {
if(!executing) {
executing = true;
//Code
console.log('Executed!');
//End code
setTimeout(function() {
executing = false;
}, 1000);
}
}
setInterval(myFunc, 100);
So in your case, this would look like this:
var executing = false;
function displayOut() {
if(!executing) {
executing = true;
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
setTimeout(function() {
executing = false;
}, 1000);
}
};
Try to use throttle (http://underscorejs.org/#throttle) or debounce (http://underscorejs.org/#debounce) from underscore, one of those should fit your needs
This one will achieve that:
function run () {
console.log('Im running');
pause(1000);
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
run();
}, s)
};
run();
The code above will run every 1 sec but if you want to make sure the function cant be runned again until you decide then you could use a flag instead like:
let canExecute = true;
function run () {
if (canExecute) {
console.log('Im running');
canExecute = false;
pause(1000);
}
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
canExecute = true;
}, s)
};
run();
run();
run();
setTimeout(() =>{
run();
}, 2000)
This code will execute run function twice, first on time and then one more after 2 sec.
I currently have a javascript application that plays a couple of videos and asks a series of questions, based on the wait time in each question.
However, after a new video is triggered (2th video), my code skips the first question and I can't really find out why. Any ideas? Thank you.
Settings.js
var settings = {
'appname': 'ExperimentX',
'masterpassword': 'xxxx'
};
var videos = [
{
'video': 'movie 1.mp4',
'questions': [
{
'text': `
blabla
`,
'wait': 2 * 60 + 51
},
{
'text': 'How sad are you right now',
'wait': 1 * 60 + 57
},
{
'text': '',
'wait': 57
}
]
},
{
'video': 'movie 2.mp4',
'questions': [
{
'text': 'How happy are you right now',
'wait': 2
},
{
'text': 'How sad are you right now',
'wait': 5
}
]
}
}
And the real JS code:
// -- base settings
identifier = new Date().getTime();
videos_path = 'videos/';
// -- create elements
var player = videojs('video');
var slider = $('#ex1');
// -- variables
var debug = true;
var timer = null;
var questions = [];
var currquestion = 0;
var currvideo = 0;
function log(msg){
if (debug)
console.log(msg);
}
function checkForLocalStorage(){
var result = false;
try {
result = (typeof window.localStorage == 'undefined');
} catch (err){
result = false;
}
return result;
}
function save(key, value){
log('Saving ' + key + ' -> ' + value);
var sessionObject = localStorage.getItem( identifier );
sessionObject = (null == sessionObject) ? {} : JSON.parse(sessionObject);
sessionObject[key] = value;
localStorage.setItem(identifier, JSON.stringify(sessionObject));
}
function toDate(ms){
var d = new Date(0);
d.setUTCSeconds(ms / 1000);
return d.toLocaleString();
}
function loadAll(){
var result = [];
log('Loading from localstorage:');
for (var i = 0; i < localStorage.length; i++){
var key = localStorage.key(i);
var obj = JSON.parse( localStorage.getItem(key) );
obj['timestamp'] = toDate(key);
log(obj);
result.push( obj );
}
return result;
}
function refreshVideoCount(){
log('Refreshing video counter');
$('#currvideoCounter').text( currvideo +1 );
$('#totalvideoCounter').text( videos.length );
}
function showEnd(){
log('Showing end page');
$('#ending').removeClass('hidden');
$('#videoPlayer').addClass('hidden');
$('#menuEnd').addClass('active');
$('#menuVideos').removeClass('active');
}
function showQuestion(){
console.log('Showing question, currquestion ' + currquestion + ' currvideo ' + currvideo);
clearTimeout(timer);
$('#modalTitle').html( questions[currquestion]['text'] );
$('#modalQuestion').modal('show');
$('#btnModal').on('click', function(){
log('btnModal clicked, saving answer');
save('V' + currvideo + ' Q' + currquestion, slider.slider('getValue'));
log('Refreshing slider');
slider.slider('refresh');
var next = (currquestion >= questions.length-1);
if (next == true){
log('currquestion is the last one, cycling to next video');
currvideo = currvideo +1;
currquestion = 0;
cycleVideos();
} else {
log('cycling to next question of this video');
currquestion = currquestion +1;
cycleQuestions();
}
});
}
function cycleQuestions(){
log('Resuming video');
var questionText = questions[currquestion]['text'];
var questionWait = questions[currquestion]['wait'];
player.play();
if (timer){
log('Clearing timer (cycleQuestions)');
clearTimeout(timer);
timer = null;
}
log('Setting new timer');
timer = setTimeout(function(){
log('Timer triggered, pausing player and showing question');
player.pause();
showQuestion();
}, questionWait * 1000);
}
function cycleVideos(){
log('Cycling to next video');
if (timer){
log('Clearing timer (cycleVideos)');
clearTimeout(timer);
timer = null;
}
if (currvideo > videos.length -1){
log('Video is the last one, showing end page');
player.pause();
player.exitFullscreen();
return showEnd();
}
log('Setting videofile and question variable');
videoFile = videos_path + videos[currvideo]['video'];
questions = videos[currvideo]['questions'];
refreshVideoCount();
log('Playing player');
player.src({ 'src' : videoFile });
player.play();
cycleQuestions();
}
function showOverview(){
log('Showing management page');
$('#intro').addClass('hidden');
$('#overview').removeClass('hidden');
var items = loadAll();
var content = '';
log('Generating table');
var table =
$('<table>')
.addClass('table')
.append('<thead><tr>');
for (var prop in items[0])
table.append('<th>' + prop + '</th>');
table
.append('</tr></thead>')
.append('<tbody>');
items.forEach(function(object){
// for every entry
var row = '<tr>';
for (var property in items[0]) {
if (object.hasOwnProperty(property)) {
// for every property
row = row.concat(
'<td>' + object[property] + '</td>'
);
}
}
row.concat('</tr>');
table.append(row);
});
table.append('</table>');
$('#overviewText').html(table);
$('#btnClear').on('click', function(){
log('Clearing storage');
if ( confirm('Do you really want to clear all results?') ){
localStorage.clear();
location.reload();
}
});
}
function showIntro(){
log('Showing intro page');
$('#menuIntro').addClass('active');
refreshVideoCount();
$('#intro').removeClass('hidden');
$('#introInput').keyup(function(event){
if(event.keyCode == 13)
$("#introBtn").click();
});
$('#introBtn').on('click', function(){
var name = $('#introInput').val();
var age = $('#introAge').val();
var gender = $('#introGender').val();
if (name.trim().length == 0)
return alert('You need to fill in your name.');
if (age.trim().length == 0)
return alert('You need to fill in your age.');
if (name === settings['masterpassword'])
return showOverview();
save('name', name);
save('age', age);
save('gender', gender);
$('#intro').addClass('hidden');
$('#videoPlayer').removeClass('hidden');
$('#menuIntro').removeClass('active');
$('#menuVideos').addClass('active');
slider.slider({});
player.requestFullscreen();
cycleVideos();
});
}
function disableRefresh(){
log('Disabling F5');
$(document).on("keydown", function(e){
if ((e.which || e.keyCode) == 116)
e.preventDefault();
});
}
// setup base stuff
checkForLocalStorage();
$('#logo').text( settings['appname'] );
$('#title').text( settings['appname'] );
disableRefresh();
// show intro page
showIntro( identifier );
Hi i'm relatively new to JavaScript and i'm working on a winjs app project where i want to use the Bing image search data source example in my project to virtualize the datasource of a listview.
My problem is understanding how the asynchronous functions work together and how to implement an async xhr request within the existing one.
Currently i'm using a synchronous request but i would like to change that into a asynchronous one.
This is my data adapter:
(function () {
var xxxDataAdapter = WinJS.Class.define(
function (devkey, query, delay) {
this._minPageSize = 2;
this._maxPageSize = 5;
this._maxCount = 50;
this._devkey = devkey;
this._query = query;
this._delay = 0;
},
{
getCount: function () {
var that = this;
var requestStr = 'http://xxx/' + that._query;
return WinJS.xhr({ url: requestStr, type: "GET", /*user: "foo", password: that._devkey,*/ }).then(
function (request) {
var obj = JSON.parse(request.responseText);
if (typeof obj.error === "undefined") {
var count = obj.length;
if (count === 0) { console.log("The search returned 0 results.", "sample", "error"); }
return count;
} else {
console.log("Error fetching results from API", "sample", "error");
return 0;
}
},
function (request) {
if (request && request.name === "Canceled") {
return WinJS.Promise.wrapError(request);
} else {
if (request.status === 401) {
console.log(request.statusText, "sample", "error");
} else {
console.log("Error fetching data from the service. " + request.responseText, "sample", "error");
}
return 0;
}
});
},
itemsFromIndex: function (requestIndex, countBefore, countAfter)
{
var that = this;
if (requestIndex >= that._maxCount) {
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
}
var fetchSize, fetchIndex;
if (countBefore > countAfter) {
//Limit the overlap
countAfter = Math.min(countAfter, 0);
//Bound the request size based on the minimum and maximum sizes
var fetchBefore = Math.max(Math.min(countBefore, that._maxPageSize - (countAfter + 1)), that._minPageSize - (countAfter + 1));
fetchSize = fetchBefore + countAfter + 1;
fetchIndex = requestIndex - fetchBefore;
} else {
countBefore = Math.min(countBefore, 10);
var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
fetchSize = countBefore + fetchAfter + 1;
fetchIndex = requestIndex - countBefore;
}
var requestStr = 'http://xxx/' + that._query;
return WinJS.xhr({ url: requestStr, type: "GET", /*user: "foo", password: that._devkey,*/ }).then(
function (request)
{
var results = [], count;
var obj = JSON.parse(request.responseText);
if (typeof obj.error === "undefined")
{
var items = obj;
for (var i = 0, itemsLength = items.length; i < itemsLength; i++)
{
var dataItem = items[i];
var req = new XMLHttpRequest();
// false = synchronous
req.open("get", "http://xxxxx/" + dataItem.id, false);
req.send();
var jobj = JSON.parse(req.response);
if (typeof jobj.error === "undefined")
{
results.push({
key: (fetchIndex + i).toString(),
data: {
title: jobj.name.normal,
date: Date.jsonFormat(dataItem.calculatedAt, "Do, MMM HH:mm Z"),
result: "",
status: "",
}
});
}
}
return {
items: results, // The array of items
offset: requestIndex - fetchIndex, // The offset into the array for the requested item
};
} else {
console.log(request.statusText, "sample", "error");
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
}
},
function (request)
{
if (request.status === 401) {
console.log(request.statusText, "sample", "error");
} else {
console.log("Error fetching data from the service. " + request.responseText, "sample", "error");
}
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.noResponse));
}
);
}
});
WinJS.Namespace.define("xxx", {
datasource: WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function (devkey, query, delay) {
this._baseDataSourceConstructor(new xxxDataAdapter(devkey, query, delay));
})
});
})();
And this is the synchronous request i would like to change to an asynchronous one:
var req = new XMLHttpRequest();
// false = synchronous
req.open("get", "http://xxxxx/" + dataItem.id, false);
req.send();
you can use then function to chain promises. In your scenario, then function need to simple have a if statement.
return WinJS.xhr(params).then(function (req)
{
if (..)
return WinJS.xhr(params2);
else
return; // then function ensures wrapping your sync result in a completed promise
}, function onerror(e)
{
// todo - error handling code e.g. showing a message box based on your app requirement
});
This is what i came up with. Map the json objects received asynchronously and make another asynchronous call for each object to get additional data. Then the nested async calls are joined and returned when all are finished.
return WinJS.xhr({ url: 'http://xxx=' + that._query }).then(function (request) {
var results = [];
var obj = JSON.parse(request.responseText);
var xhrs = obj.map(function (dataItem, index) {
return WinJS.xhr({ url: 'http://xxxx' + dataItem.attrx }).then(
function completed(nestedRequest) {
var xxJobj = JSON.parse(nestedRequest.responseText);
var dataObj = {};
dataObj.title = xxJobj.name;
dataObj.date = Date.jsonFormat(dataItem.attrtrxx, "Do, MMM HH:mm Z");
dataObj.result = "open";
dataObj.status = "foo";
if (dataItem.xx.hasOwnProperty("attrx5")) {
dataObj.opponent = dataItem.attrx4;
} else {
dataObj.opponent = dataItem.attrx3;
}
dataObj.page_title = "xXx";
dataObj.match_id = dataItem.id;
dataObj.type = "largeListIconTextItem";
dataObj.bg_image = "http://xxx/" + xxJobj.attrx2 + "-portrait.jpg";
results.push({
key: (fetchIndex + index).toString(),
data: dataObj
});
},
function (err) {
console.log(err.status);
console.log(err.responseText);
}
);
});
return WinJS.Promise.join(xhrs).then(
function (promises) {
return {
items: results, // The array of items
offset: requestIndex - fetchIndex, // The offset into the array for the requested item
};
},
function (err) {
console.log(JSON.stringify(err));
}
);
});
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
}
};