I have this function. The purpose is to wait for an outside status to end before calling another function.
var renderEditClickWrapper = function( event )
{
var wait = false;
function waitForSavingDone(){
if (options.dataStatusHandler.getStatus() == 'saving'){
wait = setInterval( function(){
waitForSavingDone();
}, 800);
}else{
wait = false;
call.renderEdit(event.data.name, event.data.rowId, event.data.parentId, event.data.options );
}
}
if (!wait) waitForSavingDone();
return false;
};
This works, however when the functions waits once, the function is called over and over.
I'm using jQuery as well.
Any idea what I am doing wrong?
Here is one more alternative you may try:
Define a wait function as below:
function wait(waitComplete, onWaitComplete){
if (waitComplete()) {
onWaitComplete();
return true;
}
setTimeout(function(){
console.log('waiting...');
wait(waitComplete, onWaitComplete);
}, 800);
return false;
}
Event handler can use wait as below:
var renderEditClickWrapper = function( event )
{
function isWaitComplete() {
return (options.dataStatusHandler.getStatus() != 'saving');
}
function onWaitComplete() {
call.renderEdit(event.data.name, event.data.rowId,
event.data.parentId, event.data.options);
}
wait(isWaitComplete, onWaitComplete);
};
Try using clearInterval() method to cancel the interval function, instead of wait = false. And also you misunderstood the usage of interval functions. Do it like below:
var renderEditClickWrapper = function( event )
{
function waitForSavingDone() {
if (options.dataStatusHandler.getStatus() !== 'saving') {
clearInterval(wait);
}
}
var wait = setInterval(waitForSavingDone, 800);
return false;
};
You should check the callback function as mentioned in the comments. It'll be more recommended if you use callback instead.
Related
I have two functions for eg., runslider() and runslider1().
runslider() runs after the document is loaded and I need to call runslider1() after finishing runslider(). Then again runslider() after runslider1(). This process should happen like infinite loop. Can someone help me please.
I have tried to keep them like callbacks. But that didn't work.
function runSlider(runslider1){
alert("run")
runSlider1(runSlider());
}
function runSlider1(runslider){
alert("run1");
runSlider(runSlider1());
}
if you want your functions to be called over and over again try using setInterval
function runSlider(){
alert("run");
runSlider1();
}
function runSlider1(){
alert("run1");
}
setInterval(runSlider, 100);
This will cause both functions to be called in that order repeatedly every 100ms. It seems like this is the behavior you are looking for.
The comments above are correct - you will cause a stack overflow.
Don't know why you would need this, but I cleaned your code for you:
function runSlider() {
alert('run');
runSlider1();
}
function runSlider1() {
alert('run1');
runSlider();
}
You can create infinite loop like this you just need to call one function.
var runSlider = function() {
console.log("run")
runSlider1()
}
var runSlider1 = function() {
console.log("run1");
setTimeout(function() {
runSlider()
}, 1000)
}
runSlider()
Another solution is:
function runSlider() {
console.log("run");
runSlider1();
setTimeout(runSlider1(), 1000) // Calls runSlider1() after 1 second(1000 millisecond). You can change it.
}
function runSlider1() {
console.log("run1");
setTimeout(runSlider(), 1000) // Calls runSlider1() after 1 second(1000 millisecond).
}
runSlider(); // Starts the cycle
var maxCalls = 0;
function run1(cb) {
alert('run1');
if (maxCalls++ < 5) { //Added this to avoid an infinite loop
cb(run1); //We want the function run after cb to be this one
}
}
function run2(cb) {
alert('run2');
if (maxCalls++ < 5) {
cb(run2);
}
}
This is the way to call one function from another. If you create an infinite loop, you will freeze the browser up. If you want the two functions running constantly, its best to release execution for a bit with a setInterval call instead.
var runFunc = 0;
var run1 = function() {
alert('run1');
};
var run2 = function() {
alert('run2');
};
var run = function() {
!(++runFunc) ? run2 : run1; //Alternate between calling each function
}
var stopRunning = function() { //Call this to stop the functions running
clearInterval(runInterval);
};
var runInterval = setInterval(run, 1000); //Calls the function every second
I want call few function one after another recursively with setTimeout.
var flag = 0 ;
function slave1(){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
} else {
setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
}
}
}
//doing similar task
function slave2(){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT2");
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
} else {
setTimeout(slave2,2000);
}
}
}
function master() {
slave1();
console.log("Without completing slave1 function.");
slave2();
}
Through master() function I want to call multiple functions one after another, however in current situation its calling slave2() without completing slave1(). How can I make sure that slave1() has executed completed. If DOM element is not loaded than it should execute 60 times after every 2 seconds and than it should come out from slave1() and go to next one.
I want to execute same function for 60 times if dom element is not loaded without returning the control to next function.
You need to adjust slave1 to run a callback when it is finished which will be slave2.
function slave1(callback){
if(flag < 60) {
var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something.
if (COPY_PO_LINE_DIV != null) {
flag = 0;
//doing something
callback();
} else {
setTimeout(slave1,2000); //waiting for 2 seconds and checking again.
}
}
}
function slave2(){...}
function master() {
slave1(slave2);
console.log("Without completing slave1 function.");
}
This is your basic javascript chaining. If you have more slaves you might want to look into async.series otherwise you go into callback hell as Gabs00 has put it nicely:
slave1(function(){
slave2(function(){
slave3(function(){
slave4(slave5);
});
});
});
If you need to pass values to callbacks then you need to use an intermediate anonymous function which in turn calls the intended callback with the arguments in question. To do that, you need define your functions so that they use the arguments:
function slave1(str, callback){...}
function slave3(i, callback){...}
slave1("some argument", function(){
slave2("another argument", function(){
slave3(1, function(){
slave4(2, slave5);
});
});
});
Consider using promises for things like that. Here an implementation on top of jQuery, other promise libraries work similarly.
function waitForElement(elementId, maxTries, checkInterval) {
var d = $.Deferred(), intvalID, checkFunc;
// set up default values
maxTries = maxTries || 60;
checkInterval = checkInterval || 2000;
checkFunc = function () {
var elem = document.getElementById(elementId);
if (maxTries-- > 0 && elem) {
clearInterval(intvalID);
d.resolve(elem);
}
if (maxTries <= 0) {
clearInterval(intvalID);
d.reject(elementId);
}
};
// set up periodic check & do first check right-away
intvalID = setInterval(checkFunc, checkInterval);
checkFunc();
return d.promise();
}
Now, if you want to test for elements one after another, you can cascade the calls like this:
function master() {
waitForElement("DOM_ELEMENT1").done(function (elem1) {
waitForElement("DOM_ELEMENT2").done(function (elem2) {
alert("elem1 and elem2 exist!");
// now do something with elem1 and elem2
}).fail(function () {
alert("elem1 exists, but elem2 was not found.");
});
}).fail(function () {
alert("elem1 not found.");
});
}
or you can do it in parallel and have a callback called when all of the elements exist:
function master() {
$.when(
waitForElement("DOM_ELEMENT1"),
waitForElement("DOM_ELEMENT2")
)
.done(function (elem1, elem2) {
alert("elem1 and elem2 exist!");
// now do something with elem1 and elem2
})
.fail(function () {
alert("not all elements were found before the timeout");
});
}
Your slave2 function should be passed to slave1 function as a callback and should be called in slave1 after it finishes (if ever?). Your current situation is quite common, since setTimeout() function is asynchronous, thus JS interpreter doesn't wait till the function is completed, but sets the setTimeout() result at the end of the Evet Loop and continues processing the master() method.
In order to pass arguments to functions, creating anonymous functions turns out to be an overkill. Consider using "bind" instead. So, if you've got
function slave1(str, callback){...}
function slave2(str, callback){...}
function slave3(i, callback){...}
function slave4(i, callback){...}
function slave5()
Instead of using
slave1("some argument", function(){
slave2("another argument", function(){
slave3(1, function(){
slave4(2, slave5);
});
});
});
Consider using
slave1("some argument",
slave2.bind(null, "another argument",
slave3.bind(null, 1,
slave4.bind(null, 2, slave5)
)
)
);
Much easier, more efficient in terms of memory and CPU utilization.
Now, how to do this with setTimeout:
slave1("some argument",
setTimeout.bind(null, slave2.bind(null, "another argument",
setTimeout.bind(null, slave3.bind(null, 1,
setTimeout.bind(null, slave4.bind(null, 2,
setTimeout.bind(null, slave5, 0)
),0)
),0)
),0)
);
I explained the problem in more detail at
http://morethanslightly.com/index.php/2014/09/executables-the-standard-solution-aka-mind-the-bind/
function addAndRemove() {
if (mapData.initialZoom && !cameraStatus.locked) {
cameraStatus.locked = true;
var ajaxRequest = null;
var abortMission = setTimeout(function () {
/* Here is where I need the event listener.
* If the function is called again then we need to
* cancel our existing ajax request */
if (ajaxRequest) {
ajaxRequest.abort();
updatePrompt({text: "Cancelled ajax"});
}
cameraStatus.locked = false;
}, 1000);
}
}
As I have stated in a comment in the code I need to be able to listen out to see if addAndRemove is called again whilst in execution. I only want to cancel the existing Ajax request if a new one has been requested. How can I do this?
You need to use a closure to create a state in your function.
You could refactor your function this way.
var addAndRemove = (function(){
var ajaxRequest = null; // --> move ajaxRequest variable here
return function () {
if (mapData.initialZoom && !cameraStatus.locked) {
cameraStatus.locked = true;
var abortMission = setTimeout(function () {
/* Here is where I need the event listener.
* If the function is called again then we need to
* cancel our existing ajax request */
if (ajaxRequest) {
ajaxRequest.abort();
updatePrompt({text: "Cancelled ajax"});
}
cameraStatus.locked = false;
}, 1000);
}
}
}());
that way ajaxRequest will point to the same reference no matter how much time your function is called.
I have read many topics about setTimeout but still i have a problem in understanding how can i implement this function to my loop.
I'll try to show you what I mean.
function RandomHit(anyArray)
{
var turechange = false;
do{
setTimeout(function(){
var random = Math.floor(Math.random()*2);
if(random===0)
{
turechange = true;
console.log(random);
}
if(random===1)
{
console.log(random);
}
}, 2000);
}while(!turechange);
}
Every time when the loop goes again, i try slow down code for a 2000 ms. But this doesn't work.
You have a problem with the one threaded nature of JavaScript (at least in this case - there are some exceptions, though).
What actually happens in your code is an endless while loop inside, in which plenty of setTimeout() functions are queued up. But as your code never actually leaves the while loop, those callbacks wont be executed.
One solution would be to trigger the next timeout function inside the setTimeout() callback like this:
function RandomHit(anyArray) {
var turechange = false;
function timerFct(){
var random = Math.floor(Math.random()*2);
if(random===0)
{
turechange = true;
console.log(random);
}
if(random===1)
{
console.log(random);
}
if( !turechange ) {
setTimeout( timerfct, 2000 );
}
}
timerFct();
}
An alternative solution would be to use setIntervall() and clearIntervall():
function RandomHit(anyArray)
{
function timerFct(){
var random = Math.floor(Math.random()*2);
if(random===0)
{
turechange = true;
console.log(random);
}
if(random===1)
{
console.log(random);
}
if( turechange ) {
clearTimeout( timeoutHandler );
}
}
var turechange = false,
timeoutHandler = setInterval( timerFct, 2000 );
}
I have to load two apis. The YouTube api which calls onYouTubePlayerReady when it has loaded and another api for SoundManager which calls soundManager.onready(...) when it has loaded. I do a lot of stuff in each of these ready functions to prepare the site. However, I also need to know when both have completed so I can do more initialization that require both to be fully loaded. Any idea how to have a function that is called when both of these ready functions are called?
Use a callback for both of them.
var callback = (function(){
var count = 0;
return function(){
count++;
if(count === 2){
//both ran and do something
}
}
})();
Then in the end of both onloads just do:
callback();
The things in that if statement will only run on the second time this function i s called.
Small fiddle demo: http://jsfiddle.net/maniator/2X8rF/
Just set a couple flags:
var aDone = false;
var bDone = false;
function whenADone(){
// do your other stuff
aDone = true;
if(bDone) whenBothDone();
}
function whenBDone(){
// do your other stuff
bDone = true;
if(aDone) whenBothDone();
}
There is probably a better way with Defered's, but this is simple and should work. Just keep track of what loaded and what didn't.
var status = {
youtube: false,
sound: false
};
var loaded = function() {
if (!status.youtube) return;
if (!status.sound) return;
// load stuff!
};
var onYoutubePlayerReady = function() {
status.youtube = true;
loaded();
};
soundManager.onready = function() {
status.sound = true;
loaded();
}
Using jQuery deferred, you could build promises for each ready function and combine them with jQuery.when to trigger a final action. For example
function promiseYoutube() {
var dfd = $.Deferred();
window.onYoutubePlayerReady = function() {
console.log("Youtube");
dfd.resolve();
};
return dfd.promise();
}
function promiseSoundManager() {
var dfd = $.Deferred();
window.soundManager.onready = function() {
console.log("SoundManager");
dfd.resolve();
};
return dfd.promise();
}
$.when( promiseYoutube(), promiseSoundManager() ).then(function(){
console.log('Youtube+SoundManager');
});
And a Fiddle simulating these callbacks http://jsfiddle.net/nikoshr/hCznB/
You could have both of your readys set a boolean to true then test against those a $(document).ready(function () { if (youTube === true && soundManager === true) { // Do stuff }});
If using jQuery, take a look at deferred:
http://www.erichynds.com/jquery/using-deferreds-in-jquery/
http://api.jquery.com/category/deferred-object/
Thanks