Run function after 1sec from loading [duplicate] - javascript

I want to have one callback function after actions are done, I'm trying something like this:
$.when(
$('#detail1').load('/getInfo.php'),
$('#detail2').load('/getOther.php')
).then(function(a,b){
alert("done");
});
The problem is that the callback function is firing before the actions are finished.

This is because jQuery.when() expects jQuery.Deferred instances while load() returns an jQuery instance (see http://api.jquery.com/jQuery.when/ and http://api.jquery.com/load/).
You can work around this issue:
// Create two Deferred instances that can be handed to $.when()
var d1 = new $.Deferred();
var d2 = new $.Deferred();
// Set up the chain of events...
$.when(d1, d2).then(function() {
alert('done');
});
// And finally: Make the actual ajax calls:
$('#detail1').load('/getInfo.php', function() { d1.resolve(); });
$('#detail2').load('/getOther.php', function() { d2.resolve(); });

I do a similar code but for images in a more dynamic way. Hope that it help.
var deferreds = [];
// Create a deferred for all images
$('.my-img-class').each(function() {
deferreds.push(new $.Deferred());
});
var i = 0;
// When image is loaded, resolve the next deferred
$('.my-img-class').load(function() {
deferreds[i].resolve();
i++;
});
// When all deferreds are done (all images loaded) do some stuff
$.when.apply(null, deferreds).done(function() {
// Do some stuff
});

Related

jQuery deferred and promise not work corectly

I have this code:
var d = $.Deferred();
var promise = d.promise();
//
promise = promise.then(function(){
var t = new $.Deferred();
var cont = $('.cont').find('> div');
requirejs(["transit"], function(){
cont.transit({opacity: .4});
//
setTimeout(function(){
cont.remove();
return t.promise();
}, 500);
});
});
//
promise.then(function() {
console.log('test');
});
//
d.resolve();
I wanna to fire up some action after another. But i need to be shure that the first one is finished. So i use promise and deferred methods. Something is not right bc second action starts before defined timeout delay. What is wrong? Can anybody help?
chain does not correctly setup?
The t promise has not been returned to the chain of d.
Modified code
var d = $.Deferred();
var promise = d.promise();
//
promise = promise.then(function(){
var t = new $.Deferred();
console.log('1st promise callback');
//var cont = $('.cont').find('> div');
setTimeout(function(){
//requirejs(["transit"], function(){
//cont.transit({opacity: .4});
//
console.log('timeout 1 func');
setTimeout(function(){
console.log('timeout 2 func');
//cont.remove();
t.resolve(true);
}, 10);
},30);
return t.promise();
});
//
promise.then(function() {
console.log('test');
});
//
d.resolve();
Output
1st promise callback (index):27
timeout 1 func (index):33
timeout 2 func (index):36
test
fiddle here
Why not use the $.when
$.when(function).done(function( x ) {
console.log('test');
});
You are using some Kind of non-Jquery, asynchronous (which is completely unnecessary if you already have jQuery) function- as asynchronous operations run on a separate thread the caller will finish nigh-instantly. If you really want to ensure sequential execution you may simply use a proper jQuery UI method (like animate : http://api.jquery.com/animate/) and add a complete-handler, as documented in the link

Issue with using jQuery deferred

I am using jQuery Deferred. I want to do 2 things when I click on a link to open modal dialog;
Call my API
Call my template (where values from API would get populated)
So I am doing the following;
self.myModel = new myModel();
self.myModel.url = "api/myModel/";
self.scenarioRecInfoDeferred = new $.Deferred();
self.myModel.fetch({
success : function(){
myModelDeferred.resolve();
}
});
self.tmplDeferred = new $.Deferred();
$.when(self.myModelDeferred, self.tmplDeferred).done(function(modalTemplates) {
});
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.tmplDeferred.resolve(modalTemplates);
});
Now I am not getting anything for "modalTemplates" inside
$.when(self.myModelDeferred, self.tmplDeferred).done(function(modalTemplates) {}
Am I doing something wrong in accessing/passing the parameter?
I believe you need 2 parameters in your .done() function handler. The first parameter will correspond to myModelDeferred arguments (which will be undefined) and the second will correspond to tmplDeferred arguments.
I made a quick jsfiddle to test myself.
var action1 = $.Deferred();
var action2 = $.Deferred();
setTimeout(function(){
action1.resolve();
}, 1000);
setTimeout(function(){
action2.resolve("def", "ghi");
}, 500);
$.when(action1.promise(), action2.promise()).done(function(args, args2){
console.log(args); // undefined
console.log(args2); // ["def", "ghi"]
});
DEMO
Hope this helps!
Why do you need to declare the deferred before loading the template?
You could do whatever you need to do with modalTemplates inside that require block and just skip the tmplDeferred use at all.
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.myModelDeferred.done(function(modalTemplates) {
});
});
Anyway, if you want to stick to that structure, I don't think that's the way to pass a variable to a deferred. You could instead assign it as self.tmplDeferred.modalTemplates=modalTemplates. So, the next should work
$.when(self.myModelDeferred, self.tmplDeferred).done(function(self.tmplDeferred.modalTemplates) {
});
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.tmplDeferred.modalTemplates=modalTemplates;
self.tmplDeferred.resolve();
});

Execute done method like in jquery after async finishes

is it possible to add on an object a listener?
For example my object does async stuff. After progress finishes
an event should be executed like the done() in jquery...
Example:
var Obj = function() {
this.load = function() {
// Load something and after finishing fire event "done"
}
}
var obj = new Obj();
obj.load().done(function(data) {
// handle data
});
Thanks for help :-)
What you want is called a promise.
Sure you need to use the deferred api :
var Obj = function(){
this.load =function(){
var deferred = = $.Deferred();
// when the condition load is fufilled
dfd.resolve(someParameters);
// if there is an error somewhere
deferred.reject();
//you need to return
return deferred.promise();
}
}
var obj = new Obj();
obj.load()
.fail(function(){ /* something went wrong! OMG */ })
.done(function(data) {
// handle data
});
Have a look at : http://api.jquery.com/deferred.done/

Using getScript synchronously

I'm writing an engine that requires the use of getScript quite extensively. I've pushed it into its own function, for ease of use, but now I need to make sure that the function itself is synchronous. Unfortunately, I can't seem to make getScript wait until the script it loads is actually finished loading before proceeding. I've even tried setting jQuery's ajax asynch property to false before making the call. I'm thinking of using jQuery's when/done protocol, but I can't seem to wrap my head around the logic of placing it inside a function and making the function itself synchronous. Any help would be very much appreciated!
function loadScript(script){
//Unrelated stuff here!!!
$.when(
$.getScript(script,function(){
//Unrelated stuff here!!!
})).done(function(){
//Wait until done, then finish function
});
}
Loop code (by request):
for (var i in divlist){
switch($("#"+divlist[i]).css({"background-color"})){
case #FFF:
loadScript(scriptlist[0],divlist[i]);
break;
case #000:
loadScript(scriptlist[2],divlist[i]);
break;
case #333:
loadScript(scriptlist[3],divlist[i]);
break;
case #777:
loadScript(scriptlist[4],divlist[i]);
break;
}
}
This worked for me, and may help you.
$.ajax({
async: false,
url: "jui/js/jquery-ui-1.8.20.min.js",
dataType: "script"
});
Basically, I just bypassed the shorthand notation and added in the async: false
As I said, it's relatively easy to chain Ajax calls with promise objects. Now, it don't see why the scripts have to be loaded one after the other, but you will have a reason for it.
First though I would get rid of the switch statement if you are only calling the same function with different arguments. E.g. you can put all the script URLs in a map:
var scripts = {
'#FFF': '...',
'#000': '...'
// etc.
};
You can chain promises by simply returning another promise from a callback passed to .then [docs]. All you need to do is start with a promise or deferred object:
var deferred = new $.Deferred();
var promise = deferred.promise();
for (var i in divlist) {
// we need an immediately invoked function expression to capture
// the current value of the iteration
(function($element) {
// chaining the promises,
// by assigning the new promise to the variable
// and returning a promise from the callback
promise = promise.then(function() {
return loadScript(
scripts[$element.css("background-color")],
$element
);
});
}($('#' + divlist[i])));
}
promise.done(function() {
// optional: Do something after all scripts have been loaded
});
// Resolve the deferred object and trigger the callbacks
deferred.resolve();
In loadScript, you simply return the promise returned from $.getScript or the one returned by .done:
function loadScript(script_url, $element){
// Unrelated stuff here!!!
return $.getScript(script_url).done(function(){
// Unrelated stuff here
// do something with $element after the script loaded.
});
}
The scripts will all be called in the order the are access in the loop. Note that if divlist is an array, you really should use normal for loop instead of a for...in loop.
Do you know that $.getScript accepts a callback function that is called synchronously after the script is loaded?
Example:
$.getScript(url,function(){
//do after loading script
});
I have 2 more solutions: a pure js one and one for multiple js load.
Try this way, create array with deferred objects and used $.when with "apply"
var scripts = [
'src/script1.js',
'src/script2.js'
];
var queue = scripts.map(function(script) {
return $.getScript(script);
});
$.when.apply(null, queue).done(function() {
// Wait until done, then finish function
});
var getScript = function(url) {
var s = document.createElement('script');
s.async = true;
s.src = url;
var to = document.getElementsByTagName('script')[0];
to.parentNode.insertBefore(s, to);
};
#Felix Kling's answer was a great start. However, I discovered that there was a slight issue with the overall attached .done() at the end of the .getScripts() returned result if I wanted to "functionalize" it. You need the last promise from the chained .getScript() iterations from within the loop. Here's the modified version of his solution (thank you, BTW).
Plugin:
(function ($) {
var fetched = new function () {
this.scripts = [];
this.set = [];
this.exists = function (url) {
var exists = false;
$.each(this.set, function (index, value) {
if ((url || '') === value) {
exists = true;
return false;
}
});
return exists;
};
this.buildScriptList = function () {
var that = this;
that.set = [];
$('script').each(function () {
var src = $(this).attr('src') || false;
if (src) {
that.set.push(src);
}
});
$.merge(this.set, this.scripts);
return this;
};
},
getScript = $.getScript;
$.getScript = function () {
var url = arguments[0] || '';
if (fetched.buildScriptList().exists(url)) {
return $.Deferred().resolve();
}
return getScript
.apply($, arguments)
.done(function () {
fetched.scripts.push(url);
});
};
$.extend({
getScripts: function (urls, cache) {
if (typeof urls === 'undefined') {
throw new Error('Invalid URL(s) given.');
}
var deferred = $.Deferred(),
promise = deferred.promise(),
last = $.Deferred().resolve();
if (!$.isArray(urls)) {
urls = [urls];
}
$.each(urls, function (index) {
promise = promise.then(function () {
last = $.getScript(urls[index]);
return last;
});
});
if (Boolean(cache || false) && !Boolean($.ajaxSetup().cache || false)) {
$.ajaxSetup({cache: true});
promise.done(function () {
$.ajaxSetup({cache: false});
});
}
deferred.resolve();
return last;
}
});
})($);
You can ignore the fetched function (I implemented it to reduce potential redundant calls - which is why I hijacked .getScript()) and see where the variable last is set inside the .getScripts() method. It defaults to a resolved deferred object, so that if the urls array is empty, it's passed to the returned result to attach the outer .done() call to. Otherwise, it will inevitably be assigned the last promise object from the chained .getScript() calls and thus will ensure everything will remain synchronous from outside the function.
Returning the initially created deferred object will not work if you resolve it before returning it back to the invoker (which is what you're supposed to do per jQuery's official documentation).
Example:
function loadStuff(data) {
var version = {
'accounting': '1.2.3',
'vue': '1.2.3',
'vueChart': '1.2.3'
};
$.getScripts([
'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/' + version.accounting + '/accounting.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue/' + version.vue + '/vue.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/' + version.vueChart + '/vue-chartjs.min.js'
], true)
.done(function () {
// do stuff
})
.fail(function () {
throw new Error('There was a problem loading dependencies.');
});
}
Just create a script node, set its src property to the JS you want to load then append it to the head:
var myScript = document.createElement('script');
myScript.src = "thesource.js";
document.head.appendChild(myScript);
this is what I do
function loadJsFile(filename) {
$.ajaxSetup({
cache: true
});
var dloadJs = new $.Deferred();
$.when(dloadJs).done(function () {
$.ajaxSetup({
cache: false
});
});
dloadJs.resolve(
$.getScript(filename, function () { })
);
}

Wait till a Function with animations is finished until running another Function

I'm having an issue with normal (non-ajax) functions that involve lots of animations within each of them. Currently I simply have a setTimeout between functions, but this isn't perfect since no browsers / computers are the same.
Additional Note: They both have separate animations/etc that collide.
I can't simply put one in the callback function of another
// multiple dom animations / etc
FunctionOne();
// What I -was- doing to wait till running the next function filled
// with animations, etc
setTimeout(function () {
FunctionTwo(); // other dom animations (some triggering on previous ones)
}, 1000);
Is there anyway in js/jQuery to have:
// Pseudo-code
-do FunctionOne()
-when finished :: run -> FunctionTwo()
I know about $.when() & $.done(), but those are for AJAX...
MY UPDATED SOLUTION
jQuery has an exposed variable (that for some reason isn't listed anywhere in the jQuery docs) called $.timers, which holds the array of animations currently taking place.
function animationsTest (callback) {
// Test if ANY/ALL page animations are currently active
var testAnimationInterval = setInterval(function () {
if (! $.timers.length) { // any page animations finished
clearInterval(testAnimationInterval);
callback();
}
}, 25);
};
Basic useage:
// run some function with animations etc
functionWithAnimations();
animationsTest(function () { // <-- this will run once all the above animations are finished
// your callback (things to do after all animations are done)
runNextAnimations();
});
You can use jQuery's $.Deferred
var FunctionOne = function () {
// create a deferred object
var r = $.Deferred();
// do whatever you want (e.g. ajax/animations other asyc tasks)
setTimeout(function () {
// and call `resolve` on the deferred object, once you're done
r.resolve();
}, 2500);
// return the deferred object
return r;
};
// define FunctionTwo as needed
var FunctionTwo = function () {
console.log('FunctionTwo');
};
// call FunctionOne and use the `done` method
// with `FunctionTwo` as it's parameter
FunctionOne().done(FunctionTwo);
you could also pack multiple deferreds together:
var FunctionOne = function () {
var
a = $.Deferred(),
b = $.Deferred();
// some fake asyc task
setTimeout(function () {
console.log('a done');
a.resolve();
}, Math.random() * 4000);
// some other fake asyc task
setTimeout(function () {
console.log('b done');
b.resolve();
}, Math.random() * 4000);
return $.Deferred(function (def) {
$.when(a, b).done(function () {
def.resolve();
});
});
};
http://jsfiddle.net/p22dK/
add the following to the end of the first function
return $.Deferred().resolve();
call both functions like so
functionOne().done(functionTwo);
Along with Yoshi's answer, I have found another very simple (callback type) solution for animations.
jQuery has an exposed variable (that for some reason isn't listed anywhere in the jQuery docs) called $.timers, which holds the array of animations currently taking place.
function animationsTest (callback) {
// Test if ANY/ALL page animations are currently active
var testAnimationInterval = setInterval(function () {
if (! $.timers.length) { // any page animations finished
clearInterval(testAnimationInterval);
callback();
}
}, 25);
};
Basic useage:
functionOne(); // one with animations
animationsTest(functionTwo);
Hope this helps some people out!
This answer uses promises, a JavaScript feature of the ECMAScript 6 standard. If your target platform does not support promises, polyfill it with PromiseJs.
You can get the Deferred object jQuery creates for the animation using .promise() on the animation call. Wrapping these Deferreds into ES6 Promises results in much cleaner code than using timers.
You can also use Deferreds directly, but this is generally discouraged because they do not follow the Promises/A+ specification.
The resulting code would look like this:
var p1 = Promise.resolve($('#Content').animate({ opacity: 0.5 }, { duration: 500, queue: false }).promise());
var p2 = Promise.resolve($('#Content').animate({ marginLeft: "-100px" }, { duration: 2000, queue: false }).promise());
Promise.all([p1, p2]).then(function () {
return $('#Content').animate({ width: 0 }, { duration: 500, queue: false }).promise();
});
Note that the function in Promise.all() returns the promise. This is where magic happens. If in a then call a promise is returned, the next then call will wait for that promise to be resolved before executing.
jQuery uses an animation queue for each element. So animations on the same element are executed synchronously. In this case you wouldn't have to use promises at all!
I have disabled the jQuery animation queue to demonstrate how it would work with promises.
Promise.all() takes an array of promises and creates a new Promise that finishes after all promises in the array finished.
Promise.race() also takes an array of promises, but finishes as soon as the first Promise finished.
Is this what you mean man: http://jsfiddle.net/LF75a/
You will have one function fire the next function and so on, i.e. add another function call and then add your functionONe at the bottom of it.
Please lemme know if I missed anything, hope it fits the cause :)
or this: Call a function after previous function is complete
Code:
function hulk()
{
// do some stuff...
}
function simpsons()
{
// do some stuff...
hulk();
}
function thor()
{
// do some stuff...
simpsons();
}
ECMAScript 6 UPDATE
This uses a new feature of JavaScript called Promises
functionOne().then(functionTwo);
You can do it via callback function.
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable, function() {
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1(param, callback) {
...do stuff
callback();
}
Here is a solution for n-calls (recursive function).
https://jsfiddle.net/mathew11/5f3mu0f4/7/
function myFunction(array){
var r = $.Deferred();
if(array.length == 0){
r.resolve();
return r;
}
var element = array.shift();
// async task
timer = setTimeout(function(){
$("a").text($("a").text()+ " " + element);
var resolving = function(){
r.resolve();
}
myFunction(array).done(resolving);
}, 500);
return r;
}
//Starting the function
var myArray = ["Hi", "that's", "just", "a", "test"];
var alerting = function (){window.alert("finished!")};
myFunction(myArray).done(alerting);
You can use the javascript Promise and async/await to implement a synchronized call of the functions.
Suppose you want to execute n number of functions in a synchronized manner that are stored in an array, here is my solution for that.
async function executeActionQueue(funArray) {
var length = funArray.length;
for(var i = 0; i < length; i++) {
await executeFun(funArray[i]);
}
};
function executeFun(fun) {
return new Promise((resolve, reject) => {
// Execute required function here
fun()
.then((data) => {
// do required with data
resolve(true);
})
.catch((error) => {
// handle error
resolve(true);
});
})
};
executeActionQueue(funArray);

Categories