I got the following code:
$('#some_object_id').hide();
$('div#some_version_div').hide();
$('#some_another_object_id').show();
someFunction();
I want to issue my someFunction() only after the last of these 3 finishes its action. The problem is that from time to time they finish in different order (ie now the last may be the second, the other time the first one etc.) Now someFunction() fires without waiting for these 3 to finish. Any ideas how to fix it? Thank you.
jQuery's hide() and show() functions accept a function as their argument which is called when they finish. (aka, a callback).
$('selector').hide(function onFinish() {
console.log('done')
})
To combine three of them together, I'd convert them to a Promise, like so:
function promisify(func,selector){
return new Promise(function (resolve) {
$(selector)[func](resolve)
})
}
Promise.all([
promisify('hide', '#test'),
promisify('hide', '#test1'),
promisify('show', '#test2')
]).then(function onFinish() {
console.log('done!')
})
You can pass a callback function to hide, and show that gets executed when the animation is complete. So if you want them to execute in order just call each one in the callback of the previous one.
$('#some_object_id,div#some_version_div').hide(()=>{
$('#some_another_object_id').show(()=>{
someFunction();
});
});
And if you want to prevent a bunch of inner callbacks, and not require each animation run dependent of the others, you could use a flag. Increment the flag in each callback, check to see if its at a certain value, and then execute your function if it is.
var flag = 0;
function incrementFlag(){
flag++;
if(flag>=2){
flag=0;
someFunction();
}
}
$('#some_object_id,div#some_version_div').hide(incrementFlag);
$('#some_another_object_id').show(incrementFlag);
You could also modify the above to use a Promise, but will leave that for you to try.
You should use a variable that you initially set to 0 and increase on every complete call. As soon as the variable hit the value 3 and can call your function:
var completed = 0;
elem.hide(400, function(){
completed++;
if(completed > 2) someFunction();
});
//same for other elements...
Actually in my project I have to reapeat few functions continiously,for that i have to use setinterval or call back.which one is the best way to repeat function either call back or setInterval.lightAnim() same kind of functions i have more than 8.If i use setInterval what will be happened and if use callback what will be happened with respect to browser.which way one is best.
1st way:Using setInterval
<script>
lightAnim();
setInterval(lightAnim,5000);
function lightAnim() {
$(".bulb1").fadeIn(1000, function() {
$(".bulb2").fadeIn(1000, function() {
$(".bulb3").fadeIn(1000, function() {
$(".bulb4").fadeIn(1000, function() {
$(".bulb5").fadeIn(1000, function() {
$(".bulb6").fadeIn(1000);
})
});
});
});
})
}
</script>
2nd way:On complete i am calling again
<script>
lightAnim();
function lightAnim() {
$(".bulb1").fadeIn(1000, function() {
$(".bulb2").fadeIn(1000, function() {
$(".bulb3").fadeIn(1000, function() {
$(".bulb4").fadeIn(1000, function() {
$(".bulb5").fadeIn(1000, function() {
$(".bulb6").fadeIn(1000);
lightAnim();
})
});
});
});
})
}
</script>
The callback is definitely the better choice.
You don't need to sum the delays manually, and don't need to maintain it when updating the code. It's much more error-prone, as your code demonstrates: six one-second delays are not 5000 milliseconds. Your first snippet would animate the first and sixth bulb simultaneously.
Also, when you are animating a single element the animations would get chained onto jQuery's animation queue. If the timers deviate (and setInterval is known to drift over longer periods), then you could easily build up a very long queue (animations are scheduled faster than they are executed) which is not good for performance.
I'm working on an interactive tutorial-tool for JavaScript. The core of the tool is the script of the tutorial. The script will trigger various functions that run animations, speaker-voices load new pages etc. Three sample calls(most tutorials will have 10-100s of calls, so a neat overview of the calls is highly desired:
wrap(); //wrap the page in an iframe
playsound('media/welcome') //playing a sound (duh)
highlight('[name=firstname]'); //animation that highlights an element.
playsound('media/welcome2');
loadpage(page2); //loading a new page
All calls have something in common: they have non-normal-triggers. In this simple script for example, the second call should be triggered once the iframe in the first call is loaded. The third script is triggered once the sound is complete (ie delay). The fourth function should be triggered once the animation is complete. The fifth event should be triggered on an event (for example a click).
A technical solution to this would be to call the function in the callback of the previous function, this has the potential to get pretty messy. What I like with a solution wherer the functions are called lite this is that someone with a little bit of brains, but no coding experience could hammer up a script of their own. How would you solve this? I'm pretty new to javascript so if you could be explicit i'd appreciate it.
I'd use a per-built solution. There is bound be one that fits your needs. Something simple like jTour or if that doesn't cover it something a little more complex like Scriptio. Some of the answers to this question may also be of interest to you.
Edit
If you don't want to use a preexisting solution, I'd do something like this:
var runTutorial = (function () {
// The command object holds all the different commands that can
// be used by someone for the tutorial. Each of these commands
// will recive a callback set as their `this`. This
// callback should be called by your commands when they are done
// running. The person making the tutorial won't need to know
// about the callback, the code will handle that.
var commands = {
wrap: function () {
//wrap the page in an iframe
this();
},
playsound: function (soundPath, soundLength) {
//playing a sound (duh)
setTimeout(this, soundLength);
},
highlight: function (selector) {
//animation that highlights an element.
//I'm using jQuery UI for the animation here,
// but most animation libraries should provide
// a callback for when the animation is done similarly
$(selector).effect('highlight', 'slow', this);
},
loadpage: function (pageUrl) {
//loading a new page
setTimeout(this, 500);
},
waitForClick: function () {
// when we go into the click handler `this` will no
// longer be availble to us since we will be in a
// different context, save `this` into `that` so
// we can call it later.
var that = this;
$(document).one('click', function () {
that();
});
}
},
// This function takes an array of commands
// and runs them in sequence. Each item in the
// array should be an array with the command name
// as the first item and any arguments it should be
// called with following as the rest of the items.
runTutorial = function (commandList) {
var nextCommand = function () {
if (commandList.length > 0) {
var args = commandList.shift();
// remove the command name
// from the argument list
cmd = args.shift(1);
// call the command, setting nextCommand as `this`
commands[cmd].apply(nextCommand, args);
}
}
nextCommand();
};
return runTutorial;
}());
$('#tutorialbutton').click(function() {
runTutorial([
['playsound', 'media/welcome', 1000],
['highlight', '[name=firstname]'],
['playsound', 'media/welcome2', 1500],
['waitForClick'],
['loadpage', page2],
['playsound', 'media/page2', 100]
]);
});
The runTutorial function takes a simple array containing the commands in the order they should be run, along with their parameters. No need to bother the person writing the script with callbacks, runTutorial handles that for them. This has some big advantages over a system that requires the writer to manage callbacks. You don't need an unique name for each line in the script as you do with explicit callbacks, nor endless nesting of anonymous functions. You don't need to rewire anything to change the order that the commands are played in, you just physically rearrange them in the array.
jsfiddle you can play with
Each of your commands will need to wait for its action to be done before it calls its callback (aka this). I simulate this in the fiddle using setTimeout. For instance, if you are using jQuery's .animate for highlight, it provides a complete handler that fires when the animation is done, just stick this (with out the invocation parentheses ()) there. If you are using jQuery UI, it has a built-in 'highlight' effect, so you could implement it like this:
highlight: function (selector) {
//animation that highlights an element.
$(selector).effect('highlight', 'slow', this);
},
Most other libraries that provide animations should provide a similar callback option you can use.
Controlling the callback for the sounds may be harder depending on how you are playing them. If the method you are using doesn't provide a callback or a way of polling it to see if it is done yet you might just have to add another parameter to playsound that takes the length of the sound in ms and then waits that long before proceeding:
playsound: function (soundPath, soundLength) {
//playing a sound (duh)
setTimeout(this, soundLength);
},
Callbacks are your best bet, I think. They don't have to be messy (though it's certainly possible to make them completely incomprehensible). You could create each function to accept a callback, then use a structure like this to call them in sequence in a readable way:
var loadingSequence = {
start : function() { wrap(this.playsound); },
playsound : function() { playsound('media/welcome', this.highlight); },
highlight : function() { highlight('[name=firstname]', this.playsound2); },
playsound2 : function() { playsound('media/welcome2', this.loadpage); },
loadpage : function() { loadpage(page2); }
};
loadingSequence.start();
I have a jQuery Animation which I want to loop infinitely, I have the current code but it just returns nothing.
$(document).ready(function() {
var i = 0;
document.write(i);
function runTest(){
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500);
i++;
runTest();
}
if(i === 0){
runTest();
}
});
Many Thanks! :)
You could wrap them all in a function and re-call the function after the last animation has finished:
function run(){
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500,run);
}
run();
Live example: http://jsfiddle.net/nCs6N/
First off, you shouldn't chain animations like this, use callbacks:
$("#page_effect").fadeIn(1500, function() {
$(this).delay(3500).fadeOut(1500);
});
This will wait for 3500ms to fadeOut, but only after the 1500ms fadeIn is complete.
This way using callbacks, you can call the function again from the last callback:
function runTest(){
...
$('#page_effect4').delay(21000).fadeIn(1500, function() {
$(this).delay(3500).fadeOut(1500, function() {
runTest();
// this will be called only after the fadeout completes
});
});
}
You're queueing the animations, but never "yielding" execution back to the browser, because you just call the function again immediately.
The browser never gets to enter its event loop, and the animations won't start.
To fix this, you'll need to make the browser wait until all of the animations have completed, and then queue them again:
$(function() {
(function animate() {
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500);
// using deferred objects, ask for a promise that will be resolved
// when all animations on the specified elements have been completed,
// and when done, call myself to start all over again
$('#page_effect,#page_effect2,#page_effect3,#page_effect4')
.promise().done(animate);
})(); // invoke immediately
});
I note that your four separate effects are probably supposed to run in series, but the .promise() based solution above will also work if they were all running in parallel.
See http://jsfiddle.net/alnitak/ZKevs/
Note that if you are intending to run those effects in series you shouldn't really just queue them up all together - there's no timing guarantee and it's possible that the next element might start animation before the previous one finished.
The traditional solution to this was to add an "animation complete" callback in the last animation, but with four separate animations as you have here that would end up being horribly nested.
jQuery deferred objects can help here, too - note how this eliminates the additional calculated .delay() calls:
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect').promise().done(function() {
$('#page_effect2').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect2').promise().done(function() {
$('#page_effect3').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect4').promise().done(function() {
$('#page_effect4').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect4').promise.done(animate);
At which point you can see that every animation chain is identical and can be refactored:
function cycle($els) {
var i = 0, n = $els.length;
(function next() {
var $this = $els.eq(i);
i = (i + 1) % n;
$this.fadeIn(1500).delay(3500).fadeOut(1500).promise().done(next);
})();
});
cycle($('#page_effect,#page_effect2,#page_effect3,#page_effect4'));
Don't call runTest() recursively like that, you'll exhaust the function stack.
Instead use setTimeout(runTest, 0);
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>