Delay Between Functions - javascript

this is my code snippet.
function customFadeIn () {
$("img.imgKit").each(function(index) {
$(this).delay(1000*index).fadeIn("slow");
});
console.log("one runs");
}
function customFadeOut () {
$("img.imgKit").each(function(index) {
$(this).delay(1000*index).not(document.getElementById('card-6')).fadeOut("slow" , function () {
$("#card-6").delay(1000).rotate({angle:0});
});
});
console.log("two runs");
}
I want the customFadeOut runs only after customFadeIn is done, therefore I call it by this
customFadeIn();
customFadeOut();
But it did not work, I think I did something wrong here, a help would be really helpful.

You can make usage of jQuerys Deferred / promise objects. Animations do also "inherit" those objects and you can apply jQuery.when() to shoot for multiple promises to finish.
There are several ways to re-structure your code for that, a simple implementation of this could look like:
(function() {
var promises = [ ];
function customFadeIn () {
$("img.imgKit").each(function(index) {
promises.push( $(this).delay(1000*index).fadeIn("slow").promise() );
});
}
function customFadeOut () {
jQuery.when.apply( null, promises ).done(function() {
$("img.imgKit").each(function(index) {
$(this).delay(1000*index).not(document.getElementById('card-6')).fadeOut("slow" , function () {
$("#card-6").delay(1000).rotate({angle:0});
});
});
console.log("two runs");
});
}
}());
If I did everything correct there, customFadeOut sets up a listener which waits for all animations / promises to finish, before it runs its own code. You don't even have to explicitly call the .promise() method at the end, jQuery applies some white magic to link that node with a promise internally for you.
Demo: http://jsfiddle.net/RGgr3/
Looks like I did everything correct ;)

Related

Chaining dojo Deferred

I'm having trouble wrapping my head around chaining functions with "then" and Deferred objects.
I would like to have multiple functions (processes) chained together so that after one function with Async call is completely done, the other starts, and so on.
Something like:
process1().then(process2()).then(process3());
I've followed many different tutorials that do it differently but i'm still not able to get a working example.
What am I missing?
Here is a Fiddle Link
You missed the require part (require(["dojo/Deferred"]) ,modern dojo use AMD loading to load required modules, make reference in callback function that you'll use in your code .
Here is a working Fiddle
In the above fiddle I've select dojo as lib and add some coniguration as the below picture
Snippet below :
require(["dojo/Deferred",],function(Deferred){
function process1() {
var dfd = new Deferred();
// perform some async logic; resolve the promise
setTimeout(function () {
$("#output").html("process 1 complete");
dfd.resolve("process 1 complete");
}, 1000);
return dfd.promise;
}
function process2() {
var dfd = new Deferred();
// perform some async logic; resolve the promise
setTimeout(function () {
$("#output").html("process 2 complete");
dfd.resolve("process 2 complete");
}, 1000);
return dfd.promise;
}
process1().then(function (){
return process2();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output">Start</div>
Also, note that you can make multiple chaining as demonstrated in this Fiddle

Jquery .then not working

I have an accordion, and want to trigger something when it has finished transitioning from one state to another. The following code is throwing up an error Uncaught TypeError, I am just trying to console.log when it has finished for now:
$(document).ready(function () {
$('.accordion-tabs').each(function() {
$(this).children('li').first().children('a').addClass('is-active').next().addClass('is-open').show();
});
$('.accordion-tabs').on('click', 'li > a.tab-link', function(event) {
if (!$(this).hasClass('is-active')) {
event.preventDefault();
var accordionTabs = $(this).closest('.accordion-tabs');
accordionTabs.find('.is-open').removeClass('is-open').hide();
$(this).next().toggleClass('is-open').toggle();
accordionTabs.find('.is-active').removeClass('is-active');
$(this).addClass('is-active').then(
function() {
console.log( "Accordion Finished" );
});
} else {
event.preventDefault();
}
});
});
Where am I going wrong? This is the first time I have used .then!
yes it's not working, this is not the way of using it you need to learn promises first
It's used to replace (or provide an alternate way) the old callback mechanism with a cleaner way to handle asynchronous requests, instead of passing your callbacks as parameters, you can chain your function with .then, given function will be executed once the promise gets resolved.
Anyhow, this is just a basic explanation, you should really get into the books of promises for more info.
a simple example of :
var promise = new Promise(function(resolve, reject) {
if (true /* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return 123;
}).then(function (x){
console.log(x);
}).then(function (x){
console.log(x)
})

wait for function done (with setInterval) and run next function

how to run next function after first done with setInterval?
for example:
step1();
step2();
setInterval(step1, 1000).done(function() {
setInterval(step2, 1000).done( /* next step */);
});
please help me with solution!
Edit: This is an old answer. Now you can achieve this using promises also but the code will be slightly different.
If you don't want to use a promise you can use a simple flag to achieve such a thing. Please see example below:
var flag = true;
function step1() {
console.log('title');
}
function step2() {
console.log('subtitle');
}
function wrapper() {
if(flag) {
step1();
} else {
step2();
}
flag = !flag;
}
setInterval(wrapper, 30000);
If you want to chain functions on completion you can use callback functions.
Example:
function first(callback) {
console.log('Running first');
if (callback) {
callback();
}
}
function second() {
console.log('Running second function');
}
first(second);
The first function checks if a callback is used and then runs it. If there is no callback function nothing happens. You can chain functions this way.
You can also use anonymous functions.
first(function () {
console.log('This function that will run after the first one);
});
If you use setTimeout() you can't be sure whether the previous function has completed. A better way would be to use promises.
Understanding Promises
I hope I understood your question right. Good luck!
First of all setInterval can not be done by itself, it will fire infinitely if you not clear it with clearInterval.
But if you have some async action inside your function and whant to wait for it and then call another function you may just promisify it like Avraam Mavridis suggested.
function step1() {
var deferred = $.Deferred();
setTimeout(function () {
alert('I am step 1');
deferred.resolve();
}, 1000);
return deferred.promise();
}
function step2() {
alert('I am step 2');
}
step1().done(step2);
JsFiddle

Is there an easier way of chaining different jQuery actions for different selectors then nested $.when?

In jQuery you can chain actions for the same selector very easily but if you want to use different selector for each action it requires nested $.when with more then two actions which is quite hard to read and maintain.
HTML:
<span id='a'>Hello</span>
<span id='b'>world</span>
<span id='c'>!!!</span>
CSS:
span {
display: none;
}
JS: based on this: how to hide multiple items but only call the handler once?
var d = 500; // duration
// Execute in parallel.
//$('#a').show(d).hide(d);
//$('#b').show(d).hide(d);
//$('#c').show(d).hide(d);
$.when($('#a').fadeIn(d).fadeOut(d)).done(function () {
$.when($('#b').show(d).hide(d)).done(function () {
$('#c').slideDown(d).slideUp(d);
});
});
jsfiddle (old)
jsfiddle-2
I thougt I could use the queue but it seems to work only for the same selector.
Is there a way to write it in a more maintainable manner like:
pseudocode
var myActions = [];
myActions.push(function(){...});
myActions.push(function(){...});
myActions.push(function(){...});
something.executeSequentially(myActions);
EDIT:
I updated the demo so that it's a little bit harder.
If you really don't have to encounter for failures (and that's hardly possible with animations I suppose), you can use the following approach (kudos to #Esailija, as this solution is basically a simplified version of his answer):
var chainOfActions = [
function() { return $('#a').fadeIn(d).fadeOut(d); },
function() { return $('#b').fadeIn(d).fadeOut(d); },
function() { return $('#c').fadeIn(d).fadeOut(d); },
];
chainOfActions.reduce(function(curr, next) {
return curr.then(next);
}, $().promise());
Demo. There are three key points here:
each function in chain of actions already returns a promise (if not, you can 'promisify' it with returning the result of .promise() call instead)
at each step of reduce a chain is created, as each callback supplied into then() creates a new promise
the whole chain is initiated by supplying an empty promise as the initial value of reduce accumulator.
Edit, Updated
var d = 500
, something = {}
, myActions = [];
myActions.push(
function (next) {
$('#a').fadeIn(d).fadeOut(d, next)
});
myActions.push(
function (next) {
return $('#b').show(d).hide(d, next)
});
myActions.push(
function () {
return $('#c').slideDown(d).slideUp(d)
});
something.executeSequentially = function (arr) {
return $(this).queue("fx", arr);
};
something.executeSequentially(myActions);
jsfiddle http://jsfiddle.net/guest271314/2oawa1zn/

jQuery Deferreds with Chained Saves, Unified Result

I have two objects, ObjectA and ObjectB. I want to save ObjectB only after ObjectA is done, but I want to return a promise which wraps the result of both of them.
Here's my first hack at it to show the functionality that I want. This function works fine it's just ugly and surely there's a better way.
Functions saveObjectA and saveObjectB both return $.post() promises.
saveAAndBSequentially: function () {
var dfd = $.Deferred();
saveObjectA().done(function () {
saveObjectB().done(function () {
dfd.resolve();
}).fail(function () {
dfd.reject();
});
}).fail(function () {
dfd.reject();
});
return dfd.promise();
}
I'd just use $.when and add a done callback on saveObjectA to trigger saveObjectB, but the deferred for saveObjectB doesn't exist yet so I don't believe I can use $.when on it right away.
Ideas on how to solve this is a more elegant manner are greatly appreciated!
.pipe() does exactly the task you have handcoded:
var saveAAndBSequentially = function () {
return saveObjectA().pipe(function () {
return saveObjectB();
});
};

Categories

Resources