I would like to add a small dice-rolling effect to my Javascript code. I think a good way is to use the setInterval() method. My idea was the following code (just for testing):
function roleDice() {
var i = Math.floor((Math.random() * 25) + 5);
var j = i;
var test = setInterval(function() {
i--;
document.getElementById("dice").src = "./images/dice/dice" + Math.floor((Math.random() * 6) + 1) + ".png";
if (i < 1) {
clearInterval(test);
}
}, 50);
}
Now I would like to wait for the setInterval until it is done. So I added a setTimeout.
setTimeout(function(){alert("test")}, (j + 1) * 50);
This code works quite okay.
But in my main code the roleDice() function returns a value. Now I don’t know how I could handle that... I can’t return from the setTimeout(). If I add a return to the end of the function, the return will rise too fast. Does anyone have an idea, of how I could fix that?
Edit
Hmm, okay I understand what the callback does and I think I know how it works but I have still the problem. I think it’s more of an "interface" problem...
Here is my code:
function startAnimation(playername, callback) {
var i = Math.floor((Math.random() * 25) + 5);
var int = setInterval(function() {
i--;
var number = Math.floor((Math.random() * 6) + 1);
document.getElementById("dice").src = "./images/dice/dice" + number + ".png";
if(i < 1) {
clearInterval(int);
number = Math.floor((Math.random() * 6) + 1);
addText(playername + " rolled " + number);
document.getElementById("dice").src = "./images/dice/dice" + number + ".png";
callback(number);
}
}, 50);
}
function rnd(playername) {
var callback = function(value){
return value; // I knew thats pointless...
};
startAnimation(playername, callback);
}
The function rnd() should wait and return the value… I’m a little bit confused. At the moment I have no clue how to going on... The code wait for the var callback... but how I could combine it with the return? I would like to run the animation and return after that the last number with rnd() to another function.
You stumbled into the pitfall most people hit at some point when they get in touch with asynchronous programming.
You cannot "wait" for an timeout/interval to finish - trying to do so would not work or block the whole page/browser. Any code that should run after the delay needs to be called from the callback you passed to setInterval when it's "done".
function rollDice(callback) {
var i = Math.floor((Math.random() * 25) + 5);
var j = i;
var test = setInterval(function() {
i--;
var value = Math.floor((Math.random() * 6) + 1);
document.getElementById("dice").src = "./images/dice/dice" + value + ".png";
if(i < 1) {
clearInterval(test);
callback(value);
}
}, 50);
}
You then use it like this:
rollDice(function(value) {
// code that should run when the dice has been rolled
});
You can now use Promises and async/await
Like callbacks, you can use Promises to pass a function that is called when the program is done running. If you use reject you can also handle errors with Promises.
function rollDice() {
return new Promise((resolve, reject) => {
const dice = document.getElementById('dice');
let numberOfRollsLeft = Math.floor(Math.random() * 25 + 5);
const intervalId = setInterval(() => {
const diceValue = Math.floor(Math.random() * 6 + 1);
// Display the dice's face for the new value
dice.src = `./images/dice/dice${diceValue}.png`;
// If we're done, stop rolling and return the dice's value
if (--numberOfRollsLeft < 1) {
clearInterval(intervalId);
resolve(diceValue);
}
}, 50);
});
}
Then, you can use the .then() method to run a callback when the promise resolves with your diceValue.
rollDice().then((diceValue) => {
// display the dice's value to the user via the DOM
})
Or, if you're in an async function, you can use the await keyword.
async function takeTurn() {
// ...
const diceValue = await rollDice()
// ...
}
Orginally your code was all sequential. Here is a basic dice game where two players roll one and they see who has a bigger number. [If a tie, second person wins!]
function roleDice() {
return Math.floor(Math.random() * 6) + 1;
}
function game(){
var player1 = roleDice(),
player2 = roleDice(),
p1Win = player1 > player2;
alert( "Player " + (p1Win ? "1":"2") + " wins!" );
}
game();
The code above is really simple since it just flows. When you put in a asynchronous method like that rolling the die, you need to break up things into chunks to do processing.
function roleDice(callback) {
var i = Math.floor((Math.random() * 25) + 5);
var j = i;
var test = setInterval(function(){
i--;
var die = Math.floor((Math.random() * 6) + 1);
document.getElementById("dice").src = "./images/dice/dice" + die + ".png";
if(i < 1) {
clearInterval(test);
callback(die); //Return the die value back to a function to process it
}
}, 50);
}
function game(){
var gameInfo = { //defaults
"p1" : null,
"p2" : null
},
playerRolls = function (playerNumber) { //Start off the rolling
var callbackFnc = function(value){ //Create a callback that will
playerFinishes(playerNumber, value);
};
roleDice( callbackFnc );
},
playerFinishes = function (playerNumber, value) { //called via the callback that role dice fires
gameInfo["p" + playerNumber] = value;
if (gameInfo.p1 !== null && gameInfo.p2 !== null ) { //checks to see if both rolls were completed, if so finish game
giveResult();
}
},
giveResult = function(){ //called when both rolls are done
var p1Win = gameInfo.p1 > gameInfo.p2;
alert( "Player " + (p1Win ? "1":"2") + " wins!" );
};
playerRolls("1"); //start player 1
playerRolls("2"); //start player 2
}
game();
The above code could be better in more of an OOP type of way, but it works.
There are a few issues for the above solutions to work. Running the program doesn't (at least not in my preferred browser) show any images, so these has to be loaded before running the game.
Also, by experience I find the best way to initiate the callback method in cases like preloading N images or having N players throw a dice is to let each timeout function do a countdown to zero and at that point execute the callback. This works like a charm and does not rely on how many items needing to be processed.
<html><head><script>
var game = function(images){
var nbPlayers = 2, winnerValue = -1, winnerPlayer = -1;
var rollDice = function(player,callbackFinish){
var playerDice = document.getElementById("dice"+player);
var facesToShow = Math.floor((Math.random() * 25) + 5);
var intervalID = setInterval(function(){
var face = Math.floor(Math.random() * 6);
playerDice.src = images[face].src;
if (--facesToShow<=0) {
clearInterval(intervalID);
if (face>winnerValue){winnerValue=face;winnerPlayer=player}
if (--nbPlayers<=0) finish();
}
}, 50);
}
var finish = function(){
alert("Player "+winnerPlayer+" wins!");
}
setTimeout(function(){rollDice(0)},10);
setTimeout(function(){rollDice(1)},10);
}
var preloadImages = function(images,callback){
var preloads = [], imagesToLoad = images.length;
for (var i=0;i<images.length;++i){
var img=new Image();
preloads.push(img);
img.onload=function(){if(--imagesToLoad<=0)callback(preloads)}
img.src = images[i];
}
}
preloadImages(["dice1.png","dice2.png","dice3.png","dice4.png","dice5.png","dice6.png"],game);
</script></head><body>
<img src="" id="dice0" /><img src="" id="dice1" /></body></html>
To achieve that goal, using vanilla setInterval function is simply impossible. However, there is better alternative to it: setIntervalAsync.
setIntervalAsync offers the same functionality as setInterval, but it guarantees that the function will never executed more than once in a given interval.
npm i set-interval-async
Example:
setIntervalAsync(
() => {
console.log('Hello')
return doSomeWork().then(
() => console.log('Bye')
)
},
1000
)
Example with Promises & setIntervals.. this is how I created a 'flat' chain of functions that wait until the other is completed...
The below snippet uses a library called RobotJS (here it returns a color at a specific pixel on screen) to wait for a button to change color with setInterval, after which it resolves and allows the code in the main loop to continue running.
So we have a mainChain async function, in which we run functions that we declare below. This makes it clean to scale, by just putting all your await someFunctions(); one after each other:
async function mainChain() {
await waitForColorChange('91baf1', 1400, 923)
console.log('this is run after the above finishes')
}
async function waitForColorChange(colorBeforeChange, pixelColorX, pixelColorY) {
return new Promise((resolve, reject) => {
let myInterval = setInterval(() => {
let colorOfNextBtn = robot.getPixelColor(pixelColorX, pixelColorY)
if (colorOfNextBtn == colorBeforeChange) {
console.log('waiting for color change')
} else {
console.log('color has changed')
clearInterval(myInterval);
resolve();
}
}, 1000)
})
}
//Start the main function
mainChain()
Related
I am trying to change the background color of my HTML page, every 200 milliseconds using setInterval in the event of a click on the button id = 'button4'. And I want the changing of background color to stop when the user clicks on the same button again.
The code for setInterval is executed when assigned to var x whereas I want to execute it when a condition is satisfied inside the 'goCrazy' function when it is called. How can that be done?
The clearInterval is working fine and the changing of colors is stopped.
Below is my code.
var x = setInterval(() => {
const rndInt1 = randomIntFromInterval(0, 255);
const rndInt2 = randomIntFromInterval(0, 255);
const rndInt3 = randomIntFromInterval(0, 255);
document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
}, 200);
function goCrazy() {
if (document.getElementById('button4').innerText == 'Go Crazy') {
document.getElementById('button4').innerText = 'stop';
x;
}
else {
clearInterval(x);
document.getElementById('button4').innerText = 'Go Crazy';
}
}
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
You can extract the code inside setInterval into a named function, and call setInterval or clearInterval within goCrazy.
var x;
function goCrazy(){
if (document.getElementById('button4').innerText == 'Go Crazy') {
document.getElementById('button4').innerText = 'stop';
x = setInterval(changeBackground, 200);
}
else {
document.getElementById('button4').innerText = 'Go Crazy';
if (x) clearInterval(x);
}
}
function changeBackground() {
const rndInt1 = randomIntFromInterval(0, 255);
const rndInt2 = randomIntFromInterval(0, 255);
const rndInt3 = randomIntFromInterval(0, 255);
document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
}
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min)
}
The OP firstly needs to make the background changing function that is to be executed within an interval an addressable function by e.g. implementing it as function statement.
Second, the OP needs to keep track of a running/halted interval. One could achieve this by a single event handler which is aware of an own this context where one could bind at least a timeId to it and maybe even some additional button-related text-data.
The implementation of the handler function which gets registered with a button's 'click' event-listener then is very straightforward.
Depending on the null value comparison of the bound timerId one detects an either 'running' or 'halted' interval which makes it easy to continue with either clearing the running interval or starting a new interval (including the button's text-toggle).
function getRandomValue(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function setRandomBackgroundColor() {
document.body.style.backgroundColor =
`rgb(${getRandomValue(0, 255)},${getRandomValue(0, 255)},${getRandomValue(0, 255)})`;
}
function toggleBackgroundBehaviorFromBoundState({ currentTarget: elmBtn }) {
let toggleState;
if ((this.timerId ?? null) !== null) {
clearInterval(this.timerId);
// explicitly nullify value due to the above `null` comparison.
this.timerId = null;
toggleState = 'halted';
} else {
this.timerId = setInterval(setRandomBackgroundColor, 100);
toggleState = 'running';
}
elmBtn.textContent = this?.buttonCopy?.[toggleState];
}
function main() {
document
.querySelector('#button4')
.addEventListener(
'click',
toggleBackgroundBehaviorFromBoundState.bind({
buttonCopy: {
running: 'Stop',
halted: 'Go Crazy',
},
timerId: null,
})
);
}
main();
<button id="button4">Go Crazy</button>
Edit
Since the above solution has been referred to as "confusing and non-idiomatic JavaScript", the very one is taken and adapted to the seemingly to be favored this-context-free closure-style.
function getRandomValue(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function setRandomBackgroundColor() {
document.body.style.backgroundColor =
`rgb(${getRandomValue(0, 255)},${getRandomValue(0, 255)},${getRandomValue(0, 255)})`;
}
function enableBackgroundToggleForButton(elmBtn, btnCopy = {}) {
function toggleBackgroundBehavior() {
let toggleCopy;
if (timerId !== null) {
clearInterval(timerId);
timerId = null;
toggleCopy = copyHalted;
} else {
timerId = setInterval(setRandomBackgroundColor, 100);
toggleCopy = copyRunning;
}
elmBtn.textContent = toggleCopy;
}
// explicitly nullify value due to the above `null` comparison.
let timerId = null;
const {
halted: copyHalted,
running: copyRunning,
} = btnCopy;
elmBtn.addEventListener('click', toggleBackgroundBehavior);
}
enableBackgroundToggleForButton(
document.querySelector('#button4'),
{ halted: 'Go Crazy', running: 'Stop'},
);
<button id="button4">Go Crazy</button>
I can't figure out how to add a restarting timer to my simon game. I know setInterval() and SetTimeout but I can't figure out how to have the timer reset for each level if the level is passed within the first 10 seconds. Do I need an if/else to work and concatenate it to level or userClickPattern? I dont know, I tried it all.
Goal:
Have a 10 second timer that starts .click and if the pattern is completed to move to the next sequence if it is not completed then alert("... ) and restart the game. The timer function is at the bottom. Please help me!!!
var buttonColours = ["red", "blue", "green", "yellow"];
var gamePattern = [];
var userClickedPattern = [];
var started = false;
var level = 0;
$(document).keypress(function() {
if (!started) {
$("#level-title").text("Level " + level);
nextSequence();
started = true;
}
});
$(".btn").click(function() {
var userChosenColour = $(this).attr("id");
userClickedPattern.push(userChosenColour);
playSound(userChosenColour);
animatePress(userChosenColour);
checkAnswer(userClickedPattern.length - 1);
});
function checkAnswer(currentLevel) {
if (gamePattern[currentLevel] === userClickedPattern[currentLevel]) {
console.log("success");
if (userClickedPattern.length === gamePattern.length) {
setTimeout(function() {
nextSequence();
}, 1000);
}
} else {
console.log("wrong");
playSound("wrong");
$("body").addClass("game-over");
setTimeout(function() {
$("body").removeClass("game-over");
}, 200);
$("#level-title").text("Game Over, Press Any Key to Restart");
startOver();
}
}
function nextSequence() {
userClickedPattern = [];
level++;
$("#level-title").text("Level " + level);
var randomNumber = Math.floor(Math.random() * 4);
var randomChosenColour = buttonColours[randomNumber];
gamePattern.push(randomChosenColour);
$("#" + randomChosenColour).fadeIn(100).fadeOut(100).fadeIn(100);
playSound(randomChosenColour);
}
function playSound(name) {
var audio = new Audio("sounds/" + name + ".mp3");
audio.play();
}
function animatePress(currentColor) {
$("#" + currentColor).addClass("pressed");
setTimeout(function() {
$("#" + currentColor).removeClass("pressed");
}, 100);
}
function startOver() {
level = 0;
gamePattern = [];
started = false;
}
function timer() {
alert("Out Of Time Better Luck Next time");
playSound("wrong");
$("#level-title").text("Game Over, Press Any Key to Restart");
startOver();
}
Having a timer is easy with setInterval, which, unlike setTimeout, will continue to execute the handler function with the specified delay until the interval is cleared.
If you wanted the value globally, you could do:
let seconds = 0
let timerInterval
function startTimer() {
timerInterval = setInterval(() => seconds++, 1000)
}
function resetTimer() {
seconds = 0
clearInterval(timerInterval)
}
I'm trying to create a non-JQuery image slideshow, where the images fade in/out based on a timer. After a ton of research today, I believe that JavaScript's Promise functionality can do this, but it's not quite right...
My problem is that the fade in and fade out functions appear to be happening at the same time, so the image just flickers. I'm trying to adapt some of the many examples of using then() to chain the functions, but obviously something is wrong.
My logic was to:
Show the initial image on page load (via a CSS rule)
Fade out
Changing the background image URL
Fade in
My online example is here, and the JavaScript is here:
// Background images to show
var arr_Images = [
'https://cdn.pixabay.com/photo/2015/08/24/12/53/banner-904884_960_720.jpg',
'https://cdn.pixabay.com/photo/2016/11/19/22/52/coding-1841550_960_720.jpg',
'https://cdn.pixabay.com/photo/2014/05/27/23/32/matrix-356024_960_720.jpg'
];
var cycleImage = document.getElementById("cycleImage");
// Preload images
for(x = 0; x < arr_Images.length; x++)
{
var img = new Image();
img.src = arr_Images[x];
}
function fadeOutPromise(element, nextBgImgUrl) {
console.log("Fading out");
return new Promise(function(resolve) {
var op = 1; // initial opacity
var timer1 = setInterval(function () {
if (op <= 0.1){
clearInterval(timer1);
element.style.display = 'none';
cycleImage.style.backgroundImage = "url('" + nextBgImgUrl + "')";
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op -= op * 0.1;
}, 100);
resolve("Faded In");
});
}
function fadeInPromise(element) {
console.log("Fading in");
return new Promise(function(resolve) {
var op = 0.1; // initial opacity
element.style.display = 'block';
var timer2 = setInterval(function () {
if (op >= 1){
clearInterval(timer2);
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
resolve("Faded Out");
});
}
function slideShow() {
// Loop background image using array
var i = 0;
var delay = 3000;
// Loop
let imageLoopTimer = setTimeout(function tick() {
fadeOutPromise(cycleImage, arr_Images[i]).then(
fadeInPromise(cycleImage).then(function() {
i++;
if ( i >= arr_Images.length) { i = 0; }
imageLoopTimer = setTimeout(tick, delay);
})
);
}, delay);
}
slideShow();
Can somebody first explain what's wrong, then provide a solution?
You are almost there. The problem is how you resolve your promises.
What you intent to do in fade functions is:
- Create a promise
- Execute the logic with intervals
- Resolve promise
But you resolve the promise immediately, whereas you should resolve your promise once fade operation is done:
function fadeInPromise(element) {
console.log("Fading in");
return new Promise(function(resolve) {
var op = 0.1; // initial opacity
element.style.display = 'block';
var timer2 = setInterval(function () {
if (op >= 1){
clearInterval(timer2);
resolve(): // Fade is done here
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
});
}
And same thing in fadeout
Another tip for flickering
You should not change opacity that often if you want smooth effects. In css, there is already 'transition' property. So you should instead do something like this with transition:
- Show image with opacity 1
- Set opactiy to 0
- After ms, change url and set opacity to 1
setInterval() is running as a background task therefore resolve() will be fired right after the initialization of timer2.
Its pretty similar to running an async operation, but not awaiting
it.
Or with promises it would be like calling a function that returns a Promise, but wanting to access the data without a .then() callback
You need to resolve your promise inside the if (op >= 1) part for it to be actually resolved after the fadeIn/Out happened.
Check this snippet for an updated version of yours. The Promises are resolved inside the setInterval().
Here is the relevant JavaScript code of it as a direct snippet:
function fadeOutPromise(element, nextBgImgUrl) {
console.log("Fading out"+i);
return new Promise(function(resolve, reject) {
element.style.opacity = 0;
setTimeout(() => {
console.log("Fading out done"+i);
element.style.backgroundImage = "url('" + nextBgImgUrl + "')";
resolve();
}, 1000);
});
}
function fadeInPromise(element) {
console.log("Fading in"+i);
return new Promise(function(resolve, reject) {
element.style.opacity = 1;
setTimeout(resolve, 1000);
});
}
var i = 0;
var delay = 3000;
function slideShow() {
// Loop background image using array
// Loop
let imageLoopTimer = setTimeout(() => tick(), delay);
}
function tick() {
fadeOutPromise(cycleImage, arr_Images[i]).then(() =>
fadeInPromise(cycleImage).then(function() {
i++;
if ( i >= arr_Images.length) { i = 0; }
imageLoopTimer = setTimeout(() => tick(), delay);
})
);
}
Edit (with transition opacity)
I have edited the snippet and now it works with transition on opacity.
I am making a typing game using just jQuery and javascript. It worked fine as a single player game, feel free to play it at http://typetothestars.bitballoon.com/ However, I am planning to keep ratcheting up its complexity level. So I am trying to add muti player to it now.
here it is in jsfiddle minus images https://jsfiddle.net/u32s4yty/
My problem lies in my runRace functions. I was expecting the race to run for player 1, when the interval ended, it would then start again for player 2. Instead, it runs through all the iterations right away. So apperently setTimeout is not going to work here.
Any suggestions as to how to make it work?
Thanks!
// ** RUNNING GAME FUNCTIONS ** \\
//hides instructions and reveals game
function setupRace(i) {
console.log("In Race Setup")
$("#word").show();
document.getElementById("word").focus();
generateWords();
$(".toType").text(gameWords[0]);
$("#instructions").hide();
$(".wordDisplay").show();
$(".player").show();
var playerAvatar = 'url("images/' + playerInfo[i].avatar + '.png")'
$(".player").css({background: playerAvatar});
}
//game timer - IS NOT STOPPING THE OTHER FUNCTIONS FROM RUNNING
var timeoutID;
function timer(i) {
timeoutID = window.setTimeout(checkEndRace, 3000, i)
console.log("i = " + i);
console.log(playerInfo[i]);
}
function checkEndRace(i) {
console.log("in check end race - num players " + numPlayers);
if (i < numPlayers - 1) {
setupRace(i);
}else {
endRace(i);
}
}
//advances ship on correct typing
function runRace() {
console.log("In run race");
var i = 0;
while (i < playerInfo.length) {
console.log("in run race loop");
setupRace(i);
timer(i);
//timer is skipping ahead to the next iteration, eventhough
//checkEndRace hasn't run yet
var j = 1;
$(document).keyup(function(e){
var targetWord = $(".toType").text();
var typedWord = $("#word").val();
while (j < gameWords.length){
if(typedWord === targetWord){
$(".player").css({left: "+=15px",});
targetWord = $(".toType").text(gameWords[j]);
$("#word").val("");
j++;
}else {
return
};
}
});
i ++;
};
}
I was hoping to use setTimeout to stop all functions the following functions, until the interval is completed.
Calls to setTimeout return immediately and only execute once so one easy/common way to handle ordering them is to make tail calls (tick) to setTimeout and to put all requests in a queue.
// ** RUNNING GAME FUNCTIONS ** \\
var raceHandlers = [];
var raceTimout = 3000;
function tick() {
// Tail call
if (raceHandlers.length > 0) {
var action = raceHandlers.pop();
setTimeout(action[0],raceTimeout,action[1]);
}
}
//hides instructions and reveals game
function setupRace(i) {
console.log("In Race Setup")
$("#word").show();
document.getElementById("word").focus();
generateWords();
$(".toType").text(gameWords[0]);
$("#instructions").hide();
$(".wordDisplay").show();
$(".player").show();
var playerAvatar = 'url("images/' + playerInfo[i].avatar + '.png")'
$(".player").css({background: playerAvatar});
tick();
}
//advances ship on correct typing
function runRace() {
console.log("In run race");
var i = 0;
while (i < playerInfo.length) {
console.log("in run race loop");
//setupRace(i);
raceHandlers.unshift([setupRace,i]);
//timer is skipping ahead to the next iteration, eventhough
//checkEndRace hasn't run yet
var j = 1;
$(document).keyup(function(e){
var targetWord = $(".toType").text();
var typedWord = $("#word").val();
while (j < gameWords.length){
if(typedWord === targetWord){
$(".player").css({left: "+=15px",});
targetWord = $(".toType").text(gameWords[j]);
$("#word").val("");
j++;
}else {
return
};
}
});
i ++;
};
raceHandlers.unshift([endRace,playerInfo.length]);
tick();
}
I am using google maps and i am trying to put a pause in execution to prevent QUERY_LIMIT usage issue. My function that plots the addresses looks like this.
The code works, however i want to try setTimeout or setInterval to see if its going to look better on UI.
How do i call it, what should be the first argument?
Thanx alot.
vLocations = [];
for (var i = 0; i < vAddresses.length; i++) {
//pause to prevent OVER_QUERY_LIMIT issue
//geocode "free" usage limit is 5 requests per second
//setTimeout(PlotAddressesAsUnAssigned, 1000);
//sleep(500);
//this will resolve the address and store it in vLocations
AddWaypointAndUnassigned(vAddresses[i]);
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
}
Doing a pause (asynchronous execution) inside a loop (synchronous) will usually result in a lot of trouble.
You can use recursive calls that are done only when a timeout ends.
var vLocations = [];
// Manages the timeout and recursive calls
function AddWaypointAndUnassignedWithPause(index){
setTimeout(function(){
// When the timeout expires, we process the data, and start the next timeout
AddWaypointAndUnassigned(vAddresses[index]);
// Some other code you want to execute
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
if(index < vAddresses.length-1)
AddWaypointAndUnassignedWithPause(++index);
}, 1000);
}
// Start the loop
AddWaypointAndUnassignedWithPause(0);
JSFiddle example.
Try this, hope this will help
vLocations = [];
for (var i = 0; i < vAddresses.length; i++) {
//pause to prevent OVER_QUERY_LIMIT issue
setTimeout(function(){
//this will resolve the address and store it in vLocations
AddWaypointAndUnassigned(vAddresses[i]);
}, 500);
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
}
What about a waiting line, thats fired when an item is added and stopped when there are no items left.
With setTimeout:
var INTERVAL = 1000 / 5;
var to = null;
var vLocations = [];
function addAddress(vAddress) {
vLocations.push(vAddress);
startTimeout();
}
function startTimeout() {
if( to === null ) {
to = setTimout(processLocation, INTERVAL);
}
}
function processLocation() {
if( vLocations.length ) {
var vAddress = vLocations.shift();
AddWaypointAndUnassigned(vAddress);
to = setTimout(processLocation, INTERVAL);
} else {
to = null;
}
}
With setInterval:
var INTERVAL = 1000 / 5;
var to = null;
var vLocations = [];
function addAddress(vAddress) {
vLocations.push(vAddress);
startInterval();
}
function startInterval() {
if( to === null ) {
to = setInterval(processLocation, INTERVAL);
}
}
function processLocation(cb) {
if( vLocations.length ) {
var vAddress = vLocations.shift();
AddWaypointAndUnassigned(vAddress);
} else
clearInterval(to);
to = null;
}
}