I have an Ajax request waiting for response from another process.
function test() {
var flag = 0;
while (flag === 0) {
$.ajax({
url: "cs/CheckForProcess",
async: false,
success: function(data) {
if (data !== 'NotReady') {
$('#results').html(data);
flag = 1;
} else {
$('#results').html('<h1>Processing...</h1>');
setTimeout(function() {
}, 6000);
}
}
});
}
}
the problem is that the setTimout isnt working although i see in debug mode that the else condition is executed.
EDIT:
i want the next ajax request to be sent only 6 seconds after validating the process is not ready.
what am i missing?
Thx.
setTimeout is an async function. It does not pause your script. Your script will continue to run (and 6000ms later your setTimeout callback function will execute).
You could consider using setInterval to keep checking for your other condition to be true.
You could probably remove async:false by keeping track of your server response elsewhere. Once you have a successful callback then you should cancel the interval.
function test() {
var timerId = 0,
timerId = setInterval(function(){
$.ajax({
url: "cs/CheckForProcess",
success: function(data) {
if (data !== 'NotReady') {
$('#results').html(data);
clearInterval(timerId);
}
}
});
}, 6000)
}
Javascript does not have the ability to sleep (e.g. suspend or block javascript execution) using setTimeout.
A setTimeout() schedules a function to run sometime in the future and other javascript just happily keeps running during that time.
What you should do is use setTimeout() to schedule the next run of your ajax function if the data was not yet ready. So, when there is no data ready, you schedule the next ajax call for 6 seconds from now, but when you do get the data, you just process the data and you're done.
In addition, you really don't want to use async: false because that freezes the browser (doesn't allow any other processing to occur) during the ajax call. This same operation can be written to leverage the asynchronous nature of ajax and allow you to still solve your problem, but allow other processing to continue in the browser with no browser blocking. This requires asynchronous programming techniques.
You can do so like this:
function test() {
function runIt() {
$.ajax({
url: "cs/CheckForProcess",
async: true,
success: function(data) {
if (data !== 'NotReady') {
$('#results').html(data);
} else {
// if data not ready yet, then put up some progress
// and call this again in 6 seconds
$('#results').html('<h1>Processing...</h1>');
setTimeout(runIt, 6000);
}
}
});
}
// start the first iteration
runIt();
}
The setTimeout function takes a function to execute after the timeout. You are passing an empty function. So, after 6 seconds, that empty function is executing - and obviously not doing anything.
I think you are expecting setTimeout to delay the execution of other scripts on your page. This is not the case, as setTimeout delays and executes the supplied callback function in a new thread (not blocking other execution on your page).
If you are trying to do something after 6 seconds, just supply the code inside of the function() {} code you have. Eg:
setTimeout(function() {
$.ajax(...);
}, 6000);
or
setTimeout(runIt, 6000);
Links:
setTimeout documentation (mozilla)
Related SO question
I was following a video tutorial on how to do long polling, and it seems I got it done, but I'm having one issue, for some reason, though I get one response from server, my alert shows up 3-6 times. I thought "success" only happens once if we got one response.
2nd question is, how can I make this javascript code cancel the ajax call every 30 seconds, and restart it? I've put in setInterval with .abort() in there while experimenting with no luck, probably wrong placement.
Thank you for the wisdom and help!
var timestamp = null;
var imp = null;
var annk = null;
function waitForMsg(){
$.ajax(
{
type: "GET",
url: "/test?timestamp=" + timestamp + "&imp=" +imp + "&annk=" +annk,
dataType : 'json',
async: true,
cache: false,
success: function(data)
{
alert("hello");
if(data.annkr > "0"){
$("#myidone").css("background-color", "#cccccc");
}else{
$("#myidone").css("background-color", "#cccccc");
}
if(data.impr > 0){
$("#myidtwo").css("background-color", "#000000");
}else{
$("#myidtwo").css("background-color", "#000000");
}
annk = data.annkr;
imp = data.impr;
timestamp = data.timestamp;
setTimeout('waitForMsg()',2000);
}
});
}
$(document).ready(function(){
waitForMsg();
});
I read stuff on Stackoverflow about readystates, but how do I make sure it's ready only once and does it after it's ready?
If the code is exactly the one you posted, there's no reason to show the alert more than 1 and then after 2s for the rescheduling.
Can you make a jsFiddle for that showing the problem?
The second question is more interesting. You can use the timeout option in the .ajax call and then, in the error handler, just reschedule the call.
My personal suggestion is to refactor your code to use the new JQuery Ajax style base on .done .fail and .always.
And that setTimeout should be written as setTimeout(waitForMsg,2000). Using the string parameter you evaluate that string instead of just calling the function and it's a performance penalty (so small that's hardly noticeable but that is ).
You might be seeing the alert multiple times due to the setTimeout() in your success function, you keep calling the waitForMsg() function. Just a guess.
To abort the request you could do something like this:
var timer = null;
function waitForMessage() {
var req = $.ajax(YOUR_CODE);
// The 30 second timeout
timer = setTimeout(function() {
req.abort();
waitForMessage();
}, 30000);
}
Or slightly better maybe:
function waitForMsg() {
$.ajax({
timeout: 30000,
error: function(err) {
if(err === 'timeout') {
waitForMsg();
}
}
})
}
Actually you should use setInterval instead of setTimeout, using this approach if your ajax call fails, you will forcelly abort the loop.
You could also, cancel or change the timeout timings depending on the usage of your service for network resource sanity.
I'm wondering whether there's a simple way to delay the click event from being processed for a specified period of time. For example we could have
$('#someElement').on('click', 'a', function(event) {
var duration = 1000;
someAsynchronousFunction(); // Start as soon as click occurs
... // Code to delay page transition from taking place for duration specified
});
So in this case the asynchronous function would be guaranteed some amount of time to run. If it hasn't completed it's work in this time I wouldn't care and would just like to continue with the page transition. I know that it's possible to accomplish something close with
event.preventDefault();
...
setTimeout(function(){
window.location = $(this).attr('href');
}, duration);
But this only works when the link being clicked goes to a full page. I want to be able to deal with links that are used for ajax calls (which don't change the url) as well.
I noticed that the mixpanel library has a function track_links which seems to accomplish the delay on the page transition, though that function doesn't seem to work well with the support for ajax links that I mentioned.
Any help would be great! Thanks.
Edit: So I suppose my question wasn't exactly clear, so I'll try to provide some more details below.
I don't care if the async function finishes running! I only want to give it the guarantee that it has some set amount of time to execute, after which I don't care if it finishes, and would prefer to go ahead with the page transition.
i.e. I want to delay not the start of the async function, but the start of the page transition. The async function would start running as soon as the click occured.
Hopefully this is a bit more clear!
I figured out a way to solve the problem:
var secondClick = false;
var duration = 1000;
$('#someElement').on('click', 'a', function(event) {
var that = $(this);
if(!secondClick) {
event.stopPropagation();
setTimeout(function(){
secondClick = true;
that.click();
}, duration);
someAsynchronousFunction();
} else {
secondClick = false;
}
});
When the user clicks the link, it internally prevents that click from actually having any effect, and gives the asynchronous function a set amount of time to do it's work before doing a second click on the link which behaves normally.
setTimeout allows you to delay running code by however many ms you want
setTimeout(function(){
console.log('Stuff be done'); //This will be delayed for one second
}, 1000);
In reality, if you're dealing with ajax you want to respond when the ajax call is complete. It may take more or less than 1000ms. $.ajax allows you do this with the .done() method. This is an example from the docs:
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
$(this).addClass("done");
});
window.setTimeout will execute any given function after a specified delay.
You'd call it like this:
$('yourElement').click(function (event) {
setTimeout(function () { console.log('hi'); }, 1000);
});
But I have to wonder why you need to do this. What's the problem you're trying to solve? Usually delaying stuff doesn't really solve anything.
jQuery's ajax functionality provides exactly what you are looking for. You can define a callback function to run after your ajax request.
Something like this:
$('#someElement').click(function(event){
event.preventDefault();
var loc = $(this).attr('href');
$.ajax({
url: "test.html",
complete: function(){
// Handle the complete event
loc = $(this).attr('href');
window.location.href = loc;
}
});
});
You may want to use ajaxStop instead of complete, it seems like your motivation for delaying navigation is because you have a bunch of asynchronous stuff going on and you want to make sure all your ajax stuff is complete before you navigate to that page.
Regardless I would recommend looking at http://api.jquery.com/Ajax_Events/ (a very useful page of documentation).
let's say I'm doing 3 ajax calls and I want to wait for the 3 calls to finish before doing something.
Is there a library out there to synchronize multiple async events in JavaScript ? (using or not jQuery's event system)
Ex.:
var sync = new syncLib();
$('a1').click(sync.newListener());
$('a2').click(sync.newListener());
sync.wait(function(e1, e2) {
// fired when both a1 and a2 are clicked or when 10 seconds have passed
// e1 and e2 would have properties to know whether or not they timed out or not..
}, 10 /* timeout */));
I have found this one: https://github.com/Ovea/js-sync/blob/master/README.md, but timeouts are not supported. (Let's say the second ajax call takes too long, I don't want my synchronization to be hung up, I want to set a 10 secs timeout)
I know I can code something myself, but I'm just checking here (after googling for it)
Thanks!
EDIT:
Since then I found async: https://github.com/caolan/async
$.when($.ajax("/"), $.ajax("/"), $.ajax("/")).then(function () {
alert("all 3 requests complete");
});
Documentation
you can use jquery deferred object
here is a useful post http://www.erichynds.com/jquery/using-deferreds-in-jquery/
The .deferred, .when, .then solution mentioned in other answers is much more elegant, but it's also possible write your own simple solution just so you see how this can be done manually. You just set a counter for how many ajax calls you have in flight and in the success handler for each ajax calls, you decrement the counter and fire your action when the counter gets to zero.
function DoMyAjaxCalls(callbackWhenDone) {
var numAjaxCalls = 3;
// set timeout so we don't wait more than 10 seconds to fire the callback
// even if ajax calls aren't done yet
var timer = setTimeout(callbackWhenDone, 10*1000);
function checkAjaxDone() {
--numAjaxCalls;
if (numAjaxCalls == 0) {
clearTimeout(timer);
callbackWhenDone();
}
}
// first ajax call
$.ajax({
url: 'ajax/test1.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// second ajax call
$.ajax({
url: 'ajax/test2.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// third ajax call
$.ajax({
url: 'ajax/test3.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
}
Here you have a [library][1] based on jQuery made for that purpose.
In simple use-cases, $.when() is BEST but jcon-q-rency allows you to synchronize any asynchronous code sections.
http://www.megiddo.ch/jcon-q-rency
If I need call this functions one after other,
$('#art1').animate({'width':'1000px'},1000);
$('#art2').animate({'width':'1000px'},1000);
$('#art3').animate({'width':'1000px'},1000);
I know in jQuery I could do something like:
$('#art1').animate({'width':'1000px'},1000,'linear',function(){
$('#art2').animate({'width':'1000px'},1000,'linear',function(){
$('#art3').animate({'width':'1000px'},1000);
});
});
But, let's assume that I'm not using jQuery and I want to call:
some_3secs_function(some_value);
some_5secs_function(some_value);
some_8secs_function(some_value);
How I should call this functions in order to execute some_3secs_function, and AFTER that call ends, then execute some_5secs_function and AFTER that call ends, then call some_8secs_function?
UPDATE:
This still not working:
(function(callback){
$('#art1').animate({'width':'1000px'},1000);
callback();
})((function(callback2){
$('#art2').animate({'width':'1000px'},1000);
callback2();
})(function(){
$('#art3').animate({'width':'1000px'},1000);
}));
Three animations start at same time
Where is my mistake?
In Javascript, there are synchronous and asynchronous functions.
Synchronous Functions
Most functions in Javascript are synchronous. If you were to call several synchronous functions in a row
doSomething();
doSomethingElse();
doSomethingUsefulThisTime();
they will execute in order. doSomethingElse will not start until doSomething has completed. doSomethingUsefulThisTime, in turn, will not start until doSomethingElse has completed.
Asynchronous Functions
Asynchronous function, however, will not wait for each other. Let us look at the same code sample we had above, this time assuming that the functions are asynchronous
doSomething();
doSomethingElse();
doSomethingUsefulThisTime();
The functions will be initialized in order, but they will all execute roughly at the same time. You can't consistently predict which one will finish first: the one that happens to take the shortest amount of time to execute will finish first.
But sometimes, you want functions that are asynchronous to execute in order, and sometimes you want functions that are synchronous to execute asynchronously. Fortunately, this is possible with callbacks and timeouts, respectively.
Callbacks
Let's assume that we have three asynchronous functions that we want to execute in order, some_3secs_function, some_5secs_function, and some_8secs_function.
Since functions can be passed as arguments in Javascript, you can pass a function as a callback to execute after the function has completed.
If we create the functions like this
function some_3secs_function(value, callback){
//do stuff
callback();
}
then you can call then in order, like this:
some_3secs_function(some_value, function() {
some_5secs_function(other_value, function() {
some_8secs_function(third_value, function() {
//All three functions have completed, in order.
});
});
});
Timeouts
In Javascript, you can tell a function to execute after a certain timeout (in milliseconds). This can, in effect, make synchronous functions behave asynchronously.
If we have three synchronous functions, we can execute them asynchronously using the setTimeout function.
setTimeout(doSomething, 10);
setTimeout(doSomethingElse, 10);
setTimeout(doSomethingUsefulThisTime, 10);
This is, however, a bit ugly and violates the DRY principle[wikipedia]. We could clean this up a bit by creating a function that accepts an array of functions and a timeout.
function executeAsynchronously(functions, timeout) {
for(var i = 0; i < functions.length; i++) {
setTimeout(functions[i], timeout);
}
}
This can be called like so:
executeAsynchronously(
[doSomething, doSomethingElse, doSomethingUsefulThisTime], 10);
In summary, if you have asynchronous functions that you want to execute syncronously, use callbacks, and if you have synchronous functions that you want to execute asynchronously, use timeouts.
This answer uses promises, a JavaScript feature of the ECMAScript 6 standard. If your target platform does not support promises, polyfill it with PromiseJs.
Look at my answer here Wait till a Function with animations is finished until running another Function if you want to use jQuery animations.
Here is what your code would look like with ES6 Promises and jQuery animations.
Promise.resolve($('#art1').animate({ 'width': '1000px' }, 1000).promise()).then(function(){
return Promise.resolve($('#art2').animate({ 'width': '1000px' }, 1000).promise());
}).then(function(){
return Promise.resolve($('#art3').animate({ 'width': '1000px' }, 1000).promise());
});
Normal methods can also be wrapped in Promises.
new Promise(function(fulfill, reject){
//do something for 5 seconds
fulfill(result);
}).then(function(result){
return new Promise(function(fulfill, reject){
//do something for 5 seconds
fulfill(result);
});
}).then(function(result){
return new Promise(function(fulfill, reject){
//do something for 8 seconds
fulfill(result);
});
}).then(function(result){
//do something with the result
});
The then method is executed as soon as the Promise finished. Normally, the return value of the function passed to then is passed to the next one as result.
But if a Promise is returned, the next then function waits until the Promise finished executing and receives the results of it (the value that is passed to fulfill).
It sounds like you're not fully appreciating the difference between synchronous and asynchronous function execution.
The code you provided in your update immediately executes each of your callback functions, which in turn immediately start an animation. The animations, however, execute asyncronously. It works like this:
Perform a step in the animation
Call setTimeout with a function containing the next animation step and a delay
Some time passes
The callback given to setTimeout executes
Go back to step 1
This continues until the last step in the animation completes. In the meantime, your synchronous functions have long ago completed. In other words, your call to the animate function doesn't really take 3 seconds. The effect is simulated with delays and callbacks.
What you need is a queue. Internally, jQuery queues the animations, only executing your callback once its corresponding animation completes. If your callback then starts another animation, the effect is that they are executed in sequence.
In the simplest case this is equivalent to the following:
window.setTimeout(function() {
alert("!");
// set another timeout once the first completes
window.setTimeout(function() {
alert("!!");
}, 1000);
}, 3000); // longer, but first
Here's a general asynchronous looping function. It will call the given functions in order, waiting for the specified number of seconds between each.
function loop() {
var args = arguments;
if (args.length <= 0)
return;
(function chain(i) {
if (i >= args.length || typeof args[i] !== 'function')
return;
window.setTimeout(function() {
args[i]();
chain(i + 1);
}, 2000);
})(0);
}
Usage:
loop(
function() { alert("sam"); },
function() { alert("sue"); });
You could obviously modify this to take configurable wait times or to immediately execute the first function or to stop executing when a function in the chain returns false or to apply the functions in a specified context or whatever else you might need.
I believe the async library will provide you a very elegant way to do this. While promises and callbacks can get a little hard to juggle with, async can give neat patterns to streamline your thought process. To run functions in serial, you would need to put them in an async waterfall. In async lingo, every function is called a task that takes some arguments and a callback; which is the next function in the sequence. The basic structure would look something like:
async.waterfall([
// A list of functions
function(callback){
// Function no. 1 in sequence
callback(null, arg);
},
function(arg, callback){
// Function no. 2 in sequence
callback(null);
}
],
function(err, results){
// Optional final callback will get results for all prior functions
});
I've just tried to briefly explain the structure here. Read through the waterfall guide for more information, it's pretty well written.
your functions should take a callback function, that gets called when it finishes.
function fone(callback){
...do something...
callback.apply(this,[]);
}
function ftwo(callback){
...do something...
callback.apply(this,[]);
}
then usage would be like:
fone(function(){
ftwo(function(){
..ftwo done...
})
});
Since you tagged it with javascript, I would go with a timer control since your function names are 3, 5, and 8 seconds. So start your timer, 3 seconds in, call the first, 5 seconds in call the second, 8 seconds in call the third, then when it's done, stop the timer.
Normally in Javascript what you have is correct for the functions are running one after another, but since it looks like you're trying to do timed animation, a timer would be your best bet.
asec=1000;
setTimeout('some_3secs_function("somevalue")',asec*3);
setTimeout('some_5secs_function("somevalue")',asec*5);
setTimeout('some_8secs_function("somevalue")',asec*8);
I won't go into a deep discussion of setTimeout here, but:
in this case I've added the code to execute as a string. this is the simplest way to pass a var into your setTimeout-ed function, but purists will complain.
you can also pass a function name without quotes, but no variable can be passed.
your code does not wait for setTimeout to trigger.
This one can be hard to get your head around at first: because of the previous point, if you pass a variable from your calling function, that variable will not exist anymore by the time the timeout triggers - the calling function will have executed and it's vars gone.
I have been known to use anonymous functions to get around all this, but there could well be a better way,
You could also use promises in this way:
some_3secs_function(this.some_value).then(function(){
some_5secs_function(this.some_other_value).then(function(){
some_8secs_function(this.some_other_other_value);
});
});
You would have to make some_value global in order to access it from inside the .then
Alternatively, from the outer function you could return the value the inner function would use, like so:
one(some_value).then(function(return_of_one){
two(return_of_one).then(function(return_of_two){
three(return_of_two);
});
});
ES6 Update
Since async/await is widely available now, this is the way to accomplish the same:
async function run(){
await $('#art1').animate({'width':'1000px'},1000,'linear').promise()
await $('#art2').animate({'width':'1000px'},1000,'linear').promise()
await $('#art3').animate({'width':'1000px'},1000,'linear').promise()
}
Which is basically "promisifying" your functions (if they're not already asynchronous), and then awaiting them
//sample01
(function(_){_[0]()})([
function(){$('#art1').animate({'width':'10px'},100,this[1].bind(this))},
function(){$('#art2').animate({'width':'10px'},100,this[2].bind(this))},
function(){$('#art3').animate({'width':'10px'},100)},
])
//sample02
(function(_){_.next=function(){_[++_.i].apply(_,arguments)},_[_.i=0]()})([
function(){$('#art1').animate({'width':'10px'},100,this.next)},
function(){$('#art2').animate({'width':'10px'},100,this.next)},
function(){$('#art3').animate({'width':'10px'},100)},
]);
//sample03
(function(_){_.next=function(){return _[++_.i].bind(_)},_[_.i=0]()})([
function(){$('#art1').animate({'width':'10px'},100,this.next())},
function(){$('#art2').animate({'width':'10px'},100,this.next())},
function(){$('#art3').animate({'width':'10px'},100)},
]);
I use a 'waitUntil' function based on javascript's setTimeout
/*
funcCond : function to call to check whether a condition is true
readyAction : function to call when the condition was true
checkInterval : interval to poll <optional>
timeout : timeout until the setTimeout should stop polling (not 100% accurate. It was accurate enough for my code, but if you need exact milliseconds, please refrain from using Date <optional>
timeoutfunc : function to call on timeout <optional>
*/
function waitUntil(funcCond, readyAction, checkInterval, timeout, timeoutfunc) {
if (checkInterval == null) {
checkInterval = 100; // checkinterval of 100ms by default
}
var start = +new Date(); // use the + to convert it to a number immediatly
if (timeout == null) {
timeout = Number.POSITIVE_INFINITY; // no timeout by default
}
var checkFunc = function() {
var end = +new Date(); // rough timeout estimations by default
if (end-start > timeout) {
if (timeoutfunc){ // if timeout function was defined
timeoutfunc(); // call timeout function
}
} else {
if(funcCond()) { // if condition was met
readyAction(); // perform ready action function
} else {
setTimeout(checkFunc, checkInterval); // else re-iterate
}
}
};
checkFunc(); // start check function initially
};
This would work perfectly if your functions set a certain condition to true, which you would be able to poll. Plus it comes with timeouts, which offers you alternatives in case your function failed to do something (even within time-range. Think about user feedback!)
eg
doSomething();
waitUntil(function() { return doSomething_value===1;}, doSomethingElse);
waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful);
Notes
Date causes rough timeout estimates. For greater precision, switch to functions such as console.time(). Do take note that Date offers greater cross-browser and legacy support. If you don't need exact millisecond measurements; don't bother, or, alternatively, wrap it, and offer console.time() when the browser supports it
If method 1 has to be executed after method 2, 3, 4. The following code snippet can be the solution for this using Deferred object in JavaScript.
function method1(){
var dfd = new $.Deferred();
setTimeout(function(){
console.log("Inside Method - 1");
method2(dfd);
}, 5000);
return dfd.promise();
}
function method2(dfd){
setTimeout(function(){
console.log("Inside Method - 2");
method3(dfd);
}, 3000);
}
function method3(dfd){
setTimeout(function(){
console.log("Inside Method - 3");
dfd.resolve();
}, 3000);
}
function method4(){
console.log("Inside Method - 4");
}
var call = method1();
$.when(call).then(function(cb){
method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>