I'm trying to get some data in multiple functions and would like to chain them in order to execute the last function only when all data was properly loaded.
The problem is that the functions in the .done() part will be called instantly and don't wait until the Deferred-Object is resolved. I also tried it by chaining them with .then() but this also didn't work.
var array1, array2;
function doStuffWithReceivedData() {
// Working with the data
}
function getArray1() {
var defArray1 = $.Deferred();
$.getJSON(url, function(data) {
if (data.success) {
array1 = data.payload;
defArray1.resolve();
} else {
// Information displayed that there was an error
}
})
return defArray1;
}
// Function 2 is like the first one
function getArray2() {...};
$(document).read(function() {
getArray1()
.done(getArray2()
.done(doStuffWithReceivedData()));
}
The argument to .done() must be a function. You're calling the function, not passing it. Take off the parentheses.
$(document).ready(function() {
getArray1()
.done(function() {
getArray2().done(doStuffWithReceivedData));
}
}
I'm working on a big project and I simplified what it matters here. This is the code:
a = new Thing(/*sayHi + sayHey*/);
function sayHi() {
alert("hi");
}
function sayHey() {
alert("hey");
}
function Thing (callback) {
callback();
}
I'd like to, with just the callback parameter, call both the sayHi() and the sayHey() function, at the order I put them. Is it possible? How would I do it? Thank you.
Pass an anonymous function that calls both of them sequentially:
a = new Thing(function() {
sayHi();
sayHey();
});
function sayHi() {
alert("hi");
}
function sayHey() {
alert("hey");
}
function Thing (callback) {
callback();
}
Alternatively to #Barnar's answer, create and pass a regular named function. If the callback logic gets heavier, you might want that anyway.
function hiHeyCallback() {
sayHi();
sayHey();
}
a = new Thing(hiHeyCallback);
I have the following problem:
I'm trying to implement a Callback in JavaScript. Now I just made it with a global variable which holds my callbacl function. Here is the example:
_callbackFkt = null;
requestCompleted = function(oControlEvent) {
console.log("Callback: " + _callbackFkt.toString());
};
myLibRequest = function(callback) {
// some code, which is attached to the requestComplete event when ready
_callbackFkt = callback;
};
Now I try to call the functions which use the callback:
myLibRequest(function () {
// callback function 1
});
myLibRequest(function () {
// callback function 2
});
myLibRequest(function () {
// callback function 3
});
the result in the console is:
Callback: function () {
// callback function 3
}
How can I define the callback to be bound to one function call and not global available? I want the result:
Callback: function () {
// callback function 1
}
Callback: function () {
// callback function 2
}
Callback: function () {
// callback function 3
}
There are several ways to do what you are trying to do, but your basic problem is that you want a list of event handlers, but you are only assigning a single value.
To modify what you are currently doing:
_callbackFkts = [];
myLibRequest = function(callback) {
// some code, which is attached to the requestComplete event when ready
_callbackFkts.push(callback);
};
Then, when you want to execute the callbacks:
_callbackFkts.forEach(function(callbackFkt) {
callbackFkt();
});
But, this global mechanism is a bit messy. You might consider some encapsulation (untested, but you get the idea):
function Events() {
this.callbacks = [];
}
Events.protototype.bind = function(callback) {
this.callbacks.push(callback);
};
Events.prototype.executeAll = function(params) {
this.callbacks.forEach(function(callback) {
callback.apply(this, params);
}
}
Then you can use it like this:
var events = new Events();
events.bind(function() {
//callback function 1
});
events.bind(function() {
//callback function 2
});
events.bind(function() {
//callback function 3
});
events.executeAll('with', 'parameters');
Finally, you might just use an off-the-shelf event library. There are lots. One quick google search finds this.
Having a global as the callback will only work if myLibRequest() contains only synchronous code (which I assume it doesn't).
Remove the global, and use the callback that is passed in as an argument.
Assuming you have some async call in there, and you call requestCompleted when it's done. Add an argument so requestCompleted receives the callback, instead of referenceing the global.
requestCompleted = function(oControlEvent, callback) {
console.log("Callback: " + callback.toString());
};
myLibRequest = function(callback) {
myAsyncFunction(function(){
// async complete
requestCompleted('event', callback);
});
};
Hi I'm extending an existing plugin to use static JSON rather than load it from the server. This is a trimmed down version of the extension:
(function ($) {
$.fn.MyExtension = function (options) {
return this.each(function () {
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
var fromJson = function (json) {
// json stuff..
}
});
});
If I remove the $.Get and call fromJson directly without the call back I get an error saying that fromJson is not defined. This must be some form of scope issue but I cant work it out?
This isn't scope. This is timing.
A function isn't assigned to fromJson until the end of the anonymous function you pass to each.
If you call it from your get callback, then that assignment will happen before the HTTP response comes back and the function fires.
If you call it directly, then it just doesn't exist yet.
Either reorder:
return this.each(function () {
var fromJson = function (json) {
// json stuff..
}
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
});
Or use a function declaration (which will be subject to hoisting):
return this.each(function () {
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
function fromJson (json) {
// json stuff..
}
});
I have the following JavaScript code:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable);
function2(someOtherVariable);
}
else {
doThis(someVariable);
}
});
How can I ensure that function2 is called only after function1 has completed?
Specify an anonymous callback, and make function1 accept it:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable, function() {
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1(param, callback) {
...do stuff
callback();
}
If you're using jQuery 1.5 you can use the new Deferreds pattern:
$('a.button').click(function(){
if(condition == 'true'){
$.when(function1()).then(function2());
}
else {
doThis(someVariable);
}
});
Edit: Updated blog link:
Rebecca Murphy had a great write-up on this here: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/
Try this :
function method1(){
// some code
}
function method2(){
// some code
}
$.ajax({
url:method1(),
success:function(){
method2();
}
})
This answer uses promises, a JavaScript feature of the ECMAScript 6 standard. If your target platform does not support promises, polyfill it with PromiseJs.
Promises are a new (and a lot better) way to handle asynchronous operations in JavaScript:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable).then(function() {
//this function is executed after function1
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1(param, callback) {
return new Promise(function (fulfill, reject){
//do stuff
fulfill(result); //if the action succeeded
reject(error); //if the action did not succeed
});
}
This may seem like a significant overhead for this simple example, but for more complex code it is far better than using callbacks. You can easily chain multiple asynchronous calls using multiple then statements:
function1(someVariable).then(function() {
function2(someOtherVariable);
}).then(function() {
function3();
});
You can also wrap jQuery deferrds easily (which are returned from $.ajax calls):
Promise.resolve($.ajax(...params...)).then(function(result) {
//whatever you want to do after the request
});
As #charlietfl noted, the jqXHR object returned by $.ajax() implements the Promise interface. So it is not actually necessary to wrap it in a Promise, it can be used directly:
$.ajax(...params...).then(function(result) {
//whatever you want to do after the request
});
Or you can trigger a custom event when one function completes, then bind it to the document:
function a() {
// first function code here
$(document).trigger('function_a_complete');
}
function b() {
// second function code here
}
$(document).bind('function_a_complete', b);
Using this method, function 'b' can only execute AFTER function 'a', as the trigger only exists when function a is finished executing.
you can do it like this
$.when(funtion1()).then(function(){
funtion2();
})
This depends on what function1 is doing.
If function1 is doing some simple synchrounous javascript, like updating a div value or something, then function2 will fire after function1 has completed.
If function1 is making an asynchronous call, such as an AJAX call, you will need to create a "callback" method (most ajax API's have a callback function parameter). Then call function2 in the callback. eg:
function1()
{
new AjaxCall(ajaxOptions, MyCallback);
}
function MyCallback(result)
{
function2(result);
}
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>
If function1 is some sync function that you want to turn into an async one because it takes some time to complete, and you have no control over it to add a callback :
function function1 (someVariable) {
var date = Date.now ();
while (Date.now () - date < 2000); // function1 takes some time to complete
console.log (someVariable);
}
function function2 (someVariable) {
console.log (someVariable);
}
function onClick () {
window.setTimeout (() => { function1 ("This is function1"); }, 0);
window.setTimeout (() => { function2 ("This is function2"); }, 0);
console.log ("Click handled"); // To show that the function will return before both functions are executed
}
onClick ();
The output will be :
Click handled
...and after 2 seconds :
This is function 1
This is function 2
This works because calling window.setTimeout () will add a task to the JS runtine task loop, which is what an async call makes, and because the basic principle of "run-to-completion" of the JS runtime ensures that onClick () is never interrupted before it ends.
Notice that this as funny as it makes the code difficult to understand...