I have a function that include a function to an async function, but I need to return the first one when the async call has been resolved. I'm trying using
return JQuery.when()
The following function is a resume.
function getData(x){
if (x = 1){
return JQuery.when(asynFunction().then(function (data){
(...);
return;
});
}
else {
(...)
return;
}
}
The objective is that getData() doesn't return until the async call has finished.
Any idea?
Thanks for your time!
Assuming that asynFunction() returns a Promise, getData might, at its simplest, look like this :
function getData(x) {
if (x = 1) {
return asynFunction();
}
else {
var myValue = 'whatever';
return myValue;
}
}
However it's often better (though not absolutely necessary) to arrange for a function to return a Promise in all circumstances. This guarantees that wherever getData() is called, the result can be handled in an asynchronous manner (ultimately with .then or .done()) even if it is synchronously derived.
function getData(x) {
if (x = 1) {
return asynFunction();
}
else {
...
var myValue = 'whatever';
return jQuery.when(myValue);
}
}
Related
Hello Everyone hope you all doing great ,
this is my code , function with name and callback
taking the name to callback function to make return the name and console.log it
if i
function doSomething(name,callback) {
callback(name);
}
function foo(n) {
return n;
}
var val = doSomething("TEST",foo);
console.log(val);
i got undefined .
if i
function doSomething(name,callback) {
callback(name);
}
function foo(n) {
console.log(n);
}
var val = doSomething("TEST",foo);
that works fine and console.log the TEST name .
So why the return not working ?
thanks
Your doSomething() function doesn't return anything, which means an assignment using it will be undefined. But, that's not really the problem here.
The underlying problem is that you seem to be mixing two different data processing patterns here: if you're writing purely synchronous code, then use returning functions (which immediately return some value). If you need asynchronous code, then use a callback (which will "eventually" do something). Mixing those two patterns is a recipe for problems and frustration:
Either:
don't name your function a "callback", and have it return its processed value, or
make the callback responsible for doing whatever it is you were going to do with val.
Case 1:
function doSomething(data, processor) {
return processor(data);
}
function passThrough(v) { return v; }
var val = doSomething("test", passThrough);
// immediately use "val" here in for whatever thing you need to do.
Case 2:
function doSomething(data, callback) {
// _eventually_ a callback happens - for instance, this
// function pulls some data from a database, which is one
// of those inherently asynchronous tasks. Let's fake that
// with a timeout for demonstration purposes:
setTimemout(() => callback(data), 500);
}
function handleData(val) {
// use "val" here in for whatever thing you need to do. Eventually.
}
doSomething("test", handleData);
And if you want to go with case 2, you really want to have a look at "Promises" and async/await in modern Javascript, which are highly improved approaches based on the idea of "calling back once there is something to call back about".
2021 edit: a third option since original writing this answer is to use the async/await pattern, which is syntactic sugar around Promises.
Case 3:
async function doSomething(input) {
// we're still _eventually_ returning something,
// but we're now exploiting `async` to wrap a promise,
// which lets us write normal-looking code, even if what
// we're really doing is returning a Promise object,
// with the "await" keyword auto-unpacking that for us.
return someModernAsyncAPI.getThing(input);
}
function handleData(val) {
// ...
}
async function run() {
const data = await doSomething("test");
handleData(data);
}
run();
function doSomething(name,callback) {
callback(name);
}
function foo(n) {
console.log(n);
return n;
}
var val = doSomething("TEST",foo);
Take a look at above code. When you call doSomething, which internally executes foo it prints on the console because thats what console.log is for. However, after this statement it returns n as well which then is received in doSomething. But its not being returned. To put it simply, what you are mainly doing is
function doSomething(name,callback) {
const returnValue = callback(name);
}
If you call the above method, it will return undefined. To make it return correct value, you have to call "return returnValue". Similary you have to say
return callback(name)
Hope this helps.
Happy Learning
Inorder to assign the returning value/object of a function(in this case doSomething, it should have a return statement. Else the function returns nothing, so when you assign that to val, it is still undefined.
So you modify your code like this:
function doSomething(name,callback) {
return callback(name);
}
function foo(n) {
return n;
}
var val = doSomething("TEST",foo);
console.log(val);
undefined is implicitly returned if you don't have a return in your function.
when you call var val = doSomething("TEST",foo), you are aligning the return value of doSomething to val, which is undefined.
function doSomething(name,callback) {
return callback(name);
}
function foo(n) {
return n;
}
var val = doSomething("TEST",foo);
console.log(val);
What is the best way to detect when all of my asynchronous calls are finished then trigger another function? I have three querys that are triggered by the user picking a topic. These querys run and their return values are then combined to be used in a new function. The problem is I need to know when they are all done then run the new function.
function queryHandler1() {
// do something
return result1;
}
function queryHandler2() {
// do something
return result2;
}
function queryHandler3() {
// do something
return result3;
}
function alldone(result1, result2, result3) {
// do something
return result4;
}
I have tried using jquery.when(), but it only runs the first time and when the user picks a new option it does not trigger alldone?
// global
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();
function queryHandler1() {
// do something
d1.resolve();
return result1;
}
function queryHandler2() {
// do something
d2.resolve();
return result2;
}
function queryHandler3() {
// do something
d3.resolve();
return result3;
}
function alldone(result1, result2, result3) {
// do something
return result4;
}
// the top level $.when
$.when(d1, d2, d3).done(function() {
alldone();
});
How do I reset the deferred or resolve so that all done is triggered again?
Thanks for the help!
You can use Async library
For your case you can use async.parallel or async.series
depending on wether you want to run your tasks simultaneously or sequentially
To use the library in the browser https://www.jsdelivr.com/package/npm/async
I solved this issue with what I think is an inelegant solution, but it works.
function queryHandler1() {
// do something
alldone();
}
function queryHandler2() {
// do something
alldone();
}
function queryHandler3() {
// do something
alldone();
}
var numCalls = 0;
function alldone() {
if (numCalls === 2) {
// do something
console.log("YES ALL DONE");
} else {
numCalls ++;
}
}
Any improvements?
Thanks
So, we currently have something like this at for asynchronous petitions to a backend.
First: a GenericApi for all the aplications
get: function (url) {
return api_bridge ({
execute: function (auth_headers) {
return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
}
}).then(handlerSuccessResponse, handlerErrorResponse);
}
and then handler methods
//error
function handlerErrorResponse(response) {
return $q.reject(response);
}
//success
function handlerSuccessResponse(response) {
if (response.isAsync) {
return asyncStatus(response.taskId);
} else {
return $q.resolve(response);
}
}
Success got the key here, since if it is an async method, just recursively calls this method:
function asyncStatus(id){
return getAsyncStatus(id).then(function(response){
if (response.progress < 100){
return asyncStatus(id);
} else {
return getAsyncResult(id);
}
});
}
which calls either of those:
getAsyncStatus: function(id){
return get('/async/status/' + id);
},
getAsyncResult: function(id){
return get('/async/result/' + id);
},
(which call the first method of this list again).
And this way we can do a getter in such a way we don't ever care what happens under the hood:
get("/myurl")
.then(successMethod)
.catch(errorMethod);
(This will work same way whether it is asynchronous or not)
But now we would like to upgrade this system to be able to make callbacks everytime an asyncStatus call is made. Ideally something like this:
get("/myurl")
.then(successMethod)
.catch(errorMethod)
.progression(progressMethod);
The obvious way would be to pass a method as an argument through all the chain and then call it in every iteration of getAsyncStatus, but that kind of defeats the purpose of all this which is having a black box under the hood no one needs to worry about, plus changing this would imply changing all the current existing methods.
To make it the closest possible to the example I guess I would have to do something with $q.defer().notify() but I can't seem to grasp the concept right. Doing this doesn't work:
get("/myurl")
.then(successMethod, null, progressMethod)
.catch(errorMethod);
I have no clue how to make it work.
Well, apparently api_bridge method was breaking the promise binding. Found the solution is doing this:
Generic get:
get: function (url) {
var dfr = $q.defer();
dfr.resolve( api_bridge ({
execute: function (auth_headers) {
return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
}
}));
return dfr.promise.then(handlerSuccessResponse, handlerErrorResponse);
}
Handler methods (no change):
//error
function handlerErrorResponse(response) {
return $q.reject(response);
}
//success
function handlerSuccessResponse(response) {
if (response.isAsync) {
return asyncStatus(response.taskId);
} else {
return $q.resolve(response);
}
}
Recursive async method:
function asyncStatus(id){
var deferred = $q.defer();
var deferred.promise.then(null, null, angular.noop);
var deferred.notify("This is a notification");
deferred.resolve(getAsyncStatus(id).then(function(response){
if (response.progress < 100){
return asyncStatus(id);
} else {
return getAsyncResult(id);
}
}));
return deferred.promise;
}
which calls either of those (no change);
getAsyncStatus: function(id){
return get('/async/status/' + id);
},
getAsyncResult: function(id){
return get('/async/result/' + id);
},
And now we can do:
get("/myurl")
.then(successMethod, null, progressMethod)
.catch(errorMethod);
Callback progressMethod will be called everytime asyncStatus throws a notification.
I would like to do something like this
function doSomething(aPromise) {
if (/*xxx*/) {
// doSomethingElse
} else {
return aPromise
.then(doSomethingMore)
}
}
However, if i do this, aPromise will always be executed when calling doSomething. How do i lazy execute it until it get called
Try using aPromise as a function , returning Promise value from calling aPromise() at else block
function aPromise() {
return Promise.resolve(/* `Promise` return value */)
}
function doSomething(aPromise) {
if (/*xxx*/) {
// doSomethingElse
} else {
// call `aPromise()`
return aPromise()
.then(doSomethingMore)
}
}
Im trying to return a callback value after the data is loaded, Im probably looking at this all wrong.
var loadFromDatabase = function(callback){
if (!obj.data.myarray) {
// the problem is here, the jquery obj returns the ajax request obj
return $.getJSON('http://validjson',function(data){
obj.data.myarray = data.myarray;
return callback();
});
} else {
return callback();
}
};
var findObjInArray = function(){
// need i to be returned, but isnt working in the if statement, but works in the else statement
return loadFromDatabase(function(){
var l = obj.data.myarray.length;
for (var i = 0; i < 50;i++) {
if (i === 30) {
return i;
}
}
});
};
var myval = findObjInArray();
console.log(myval);
Should be just:
return callback;
Doing return callback() executes the callback function and returns its return value.
Ajax is asynchronous (hence the name). You can't return anything from it.
The getJSON method causes an HTTP request to be sent. The function you pass is called on the event when that request is answered. It has no link to the calling function.
You have to write that function to do what you want to do with the data itself. You can't pass the data back and handle it in the calling function.
you have to use one more callback function:
var loadFromDatabase = function(callback){
if (!obj.data.myarray) {
// the problem is here, the jquery obj returns the ajax request obj
return $.getJSON('http://validjson',function(data){
return callback(data.myarray);
});
} else {
return callback();
}
};
var findObjInArray = function( callback ){
// need i to be returned, but isnt working in the if statement, but works in the else statement
return loadFromDatabase(function( myarray ){
var l = myarray.length;
for (var i = 0; i < 50;i++) {
if (i === 30) {
return callback ( i );
}
}
});
};
findObjInArray(
function ( myval )
{
console.log(myval);
}
);
The problem is that the Ajax callback is called asynchronously. This means that the loadFromDatabase function returns first and then the callback is called. Therefore it is impossible to return from something from the callback.
You could use the async Ajax option to make the call asynchronous, but I don't recommend this. You need to revisit your architecture by taking into consideration the asynchronous nature of Ajax.