I have two functions. First contains jQuery.get().done() and it's return value is inside done() callback function, as showed below. (I have no idea if using jQuery matters here)
I may not be understanding something, but my functions looks similar to those in first w3 example: https://www.w3schools.com/js/js_async.asp
async function A(){
jQuery.get("example.com").done(function(result){
if (result.indexOf("Example")){
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
})
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
But the output is:
Res:undefined
// here some time passes for A() to complete.
succes
So I can't understand why .then() doesn't wait for function A() to complete and resolve promise, but instead it acts immediately while result is not defined yet ?
This is much better written using actual promises (which jQuery supports) and await as follows:
async function A() {
const result = await jQuery.get("example.com");
if (result.indexOf("Example") !== -1) {
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
}
Notes:
Stop using jQuery's .done(). It's non-standard. Use .then() or await.
Don't mix await with .done() or with .then(). Use one model or the other.
There's no need for the res intermediate variable. When you get rid of the .done(), you can just return the value directly.
Note, .indexOf() does not return a boolean. It returns -1 if not found and an index of the position if found. Best not to treat its return value as a boolean.
This isn't really a jQuery thing in particular. It's just async JS in general. I'm not sure you really need the .done() part at all since you're using promises.
But anyway, you have two basic problems.
You need to return something inside of function A, not inside .done(). So you can return jQuery.get().
In function B, you want to wait for function A to complete before hitting the .then() block. That means function B is also async. (In the simple example below you can omit the async keyword on function A.) You need to declare function B as async and then await the completion of function A.
function A() {
return jQuery.get("example.com").done(function(result) {
if (result.indexOf("Example")) {
console.log("sucess", result);
} else {
console.log("Fail", result);
}
});
}
async function B() {
await A().then(function(result) {
console.log("Res:");
// moved to a separate console log, otherwise dev tools might print
// a lot of [objectObject] instead of the actual result
console.log(result);
})
}
B();
If you want to do other stuff inside of function A and then eventually return the result, you can play around with something more like
async function A() {
const response = await jQuery.get('example.com');
// more stuff…
return response;
}
I fixed it by moving return statement outside from the .done(function(){}) and by adding await before jQuery chain. And instead of returning value inside that callback function, now I only pass there value to variable, which is later returned outside of that callback function.
async function A(){
let res = 0;
await jQuery.get("example.com").done(function(result){ //await was added
if (result.indexOf("Example")){
console.log("sucess");
res = 1; // value is passed to variable, which is returned as result outside this callback function
} else {
console.log("Fail");
res = -1;
}
})
return res; // return statement is outside the callback function
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
I guess the problem was, as #cjl750's answer says, that return statement inside the callback function isn't "seen" as a "true return statement" of that function. So function B() probably saw function A() as a function, which doesn't return anything.
EDIT
I've rewritten the code using $.Deferred() object. It's probably better now. Await is now moved to function B(), it doesn't wait for jQuery chain anymore.
function A(){
var dfd = $.Deferred();
jQuery.get("google.com").then(function(result){
if (result.indexOf("Example")){
console.log("sucess");
dfd.resolve(1);
} else {
console.log("Fail");
dfd.resolve(-1);
}
})
return dfd.promise();
}
async function B(){
await A().then(function(result){
console.log("Res:" + result);
})
}
B();
Related
I am new to Javascript and am facing trouble dealing with Async/Await. Here is my code, as per my understanding adding await puts on hold the function
Here, inside foo, it should put on hold the code at checker() and move to running the commands outside foo, but instead it executes the checker() function before console.log('the end').
function checker() {
console.log('inside checker');
return "Ok"
}
async function foo() {
let a = await checker(); // Shouldn't using await here let next line outside foo to execute
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
// Output coming is:
//1
//inside checker
//the end
//mid Ok
Can someone please tell me what properties are making it to behave this way. I know there's something that I am missing but can't figure out what.
Your checker function is not asynchronous, but you also need to do something that is actually async within it.
At the moment, all of the promises are instantly resolved which provides no opportunity for later code to run.
We need to actually create a promise, merely defining a function as async isn't enough unless something inside is returning a promise, so we return a new promise which is resolved by the setTimeout callback.
Note that the timeout period is 0 which is enough to cause the javascript event loop to be invoked, which allows the next statement(s) after calling foo to be processed. Changing this to any positive integer will change the execution time but not the order of events.
function checker() {
return new Promise(resolve => {
setTimeout(() => resolve('Ok'), 0)
})
}
function foo() {
let a = checker();
console.log(new Date(), "mid");
return a
}
(async () => {
console.log(new Date(), 'start');
foo().then(v => console.log(new Date(), 'eventually', v));
console.log(new Date(), 'the end');
})()
You didn't define your function as async
function checker() {
console.log('inside checker');
return "Ok"
}
It should be
async function checker() {
console.log('inside checker');
return "Ok"
}
await tells your code to wait for the function to finish. If you want to continue running without waiting, then you shouldn't use the await keyword. async also needs to be on the function that you want to run asynchronously, in this case checker()
async function checker() {
console.log('inside checker');
return "Ok"
}
function foo() {
let a = checker();
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
foo is an async function, ie the code inside it will wait if you use the await keyword
But the foo function returns a promise. so if you want to wait for foo either use
await foo();
or use
foo().then(() => { console.log('the end'); })
Im new to javascript and Im having an issue with Async and Await. To my understanding the async function will wait for the await function to be completed before running. I dont know if my function is written correctly but Ive tried passing no argument to the await function along with many different variations. unfortunately the logout function runs before the setStatus function is done running. Any help or direction will be greatly appreciated.
function getConfirmationToSaveAndExit() {
var retVal = confirm("Are you sure you would like to Save Item & Logout?");
if( retVal == true ) {
setStatus('Incomplete');
logout();
return true;
} else {
console.log("user does not want to continue");
return false;
}
}
function setStatus(status){
document.getElementById('filledStatus').value=status;
showLoader();
}
async function logout(){
await setStatus('Incomplete');
window.location.href="/logout";
}
setStatus(<args>) {...} function should be an async function or should return a Promise or a function invocation which returns a Promise as well. To be more precise you can even await on an async function without explicitly returning from it. e.g.:
async testFunc() {
console.log('But, all things being equal, I would rather be in Philadelphia.');
}
This function implicitly returns undefined wrapped into a Promise so you can await on it.
This is a simple version of what I'm trying to do in my application. I have an if statement which evaluates the result of a function call and then populates an array if the statement comes back as true. AFTER the if statement is completely finished, I want to run some more code such as the console.log as seen below.
I understand that the if's evaluation is taking too long to finish and javascript just continues to the console.log because of its asynchronicity. How do I make the code wait for the if statement to complete?
var tabs = [];
if (isTrue()) {
tabs.push('some string');
}
console.log(tabs[1]);
function isTrue() {
setTimeout(function() {
return true;
}, 500)
}
You can just wrap your code in a Promise and consume the returned values by calling then on it:
var tabs = [];
isTrue().then(res => {
if (res) {
tabs.push('some string');
}
return tabs;
}).then(arr => {
console.log(arr);
});
function isTrue() {
//Just wrap your existing code in a Promise constructor
return new Promise((resolve, reject) => {
setTimeout(() => {
//Pass whatever value you want to consume later to resolve
resolve(true);
}, 500)
});
}
You could pass a callback to the isTrue() function, something like:
function isTrue(_callback) {
setTimeout(function() {
// code here
// Call the callback when done
if (typeof(_callback) === 'function')
_callback(tabs);
});
}
function showTabs(tabs) {
console.log(tabs[1]);
}
isTrue(showTabs);
Ought to work.
Using modern javascript, you can achieve that using promises and async/await:
const isTrue = () => new Promise(resolve => setTimeout(resolve, 500, true));
// you can only use `await` inside an `async` function
async function main() {
// better use `let` instead of `var` since `let` is block scoped,
// see:
// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let>
let tabs = [];
if (await isTrue()) {
tabs.push('some string');
}
// array's index start by 0, not 1
console.log(tabs[0]);
}
main();
(this code also use arrow functions for isTrue.)
isTrue() returns undefined. The return true inside of the setTimeout callback will return back to the timeout call, not to the isTrue() call. The code executes immeadiately and there is no asynchronity involved (except for that timer that does nothing).
I am newbie in nodejs. Can some write me a sudo code that does the following?
Function1(); //returns an array which can be used in function2 and function3
Function2(); //returns an array which can be used in function3
Function3();
I want to run all three functions synchronously.
So function2 has to wait for function1 to finish, then use the returned array in the function2. Then function3 waits for function2 to finish, then use the returned array in the function3 and so forth.
Tried something like this but then seems execute at the same time as well.
function main() {
return Promise.resolve()
.then (function(){
function1()
})
.then (function(){
function2()
})
.then (function(){
function3()
})
}
This might be able to help you out:
function main() {
return Promise.resolve()
.then (function(){
return function1()
})
.then (function(results){
// process your results
return function2([pass arguments IF required])
})
.then (function(results){
// process your results
function3([pass arguments IF required])
})
.then (function (results) {
return results
})
.catch(function(err) {
console.log(err)
})
}
So in short what you're missing out is returning the function value which is to be captured and used by next then.
Example where each of the functions returns a promise that resolves with the return of an array which gets passed to next function where each element in array gets multiplied by 10
Starting with [1,2,3] getting passed to function2 becomes [10,20,30] which gets passed to function3 and becomes [100,200,300]
function asynchFake(data){
return new Promise((resolve)=>{
setTimeout(()=> resolve(data),1000)
})
}
function func1(){
console.log('func1')
return asynchFake([1,2,3])
}
function func2(func1Data){
console.log('func2')
return asynchFake(func1Data.map(v=>v*10));
}
function func3(func2Data){
console.log('func3')
return asynchFake(func2Data.map(v=>v*10))
}
function main() {
console.log('main')
return func1().then(func2).then(func3)
}
main().then(res=>console.log('final results', res))
You could also try async/await to make the three functions run synchronously:
function function1(){
return [1]
}
function function2(arr){
return arr.concat([2])
}
function function3(arr){
return arr.concat([3])
}
async function main(){
let res = await function1(); // waits for function1 to complete before moving to the next line
let res2 = await function2(res); // similarly waits for the completion of function2
let res3 = await function3(res2); // similarly waits for the completion of function3
console.log(res3)
console.log("end of main")
}
main()
here are 2 ways you can achieve what you are looking for. It was a bit trickier as you were using two different functions, but I think I got what you are looking for.
Utilize a callback function
Utilize the node event emitter
There are 2 ways you can achieve what you are looking for.I think I got what you are looking for.
Utilize a callback function
Utilize the node event emitter.
Asynchronous calls are an inherent part of javascript, and using callbacks is often an elegant tool to handle these calls.
However, I am not quite sure how is the branching of code following an asynchronous operation decided. For example, what would happen with the following code?
function f(callback) {
value = some_async_call();
if (value) {
callback(value);
}
return(value);
}
What would happen here? From my short JS experience, return would send back an undefined value. But suppose that value returns true from the asynchronous call, would the callback be called with the right value or with an undefined value?
In other words, is there a rule regarding which operations are executed immediately after the async call, and which are deferred until the value is returned?
What have I tried before asking
SFTW for branching asynchronous calls in javascript, but found nothing canonical or decisive.
update: added a practical difference between the 3 different approaches at the bottom
let's assume some_async_call(); is defined as an async function: async function some_async_call() { ... }
what this function returns is a Promise, which means that value is now a promise: value.then( function(result) { } )
when i translate this into code:
async function some_async_call() {
if (theMoonIsInTheRightPosition)
return Fetch('/api/data/') // this returns a promise as well.
return false;
}
i can now do 2 things:
function parentFunction(callback) {
var promise = some_async_call();
promise.then( callback );
return ...; // you can't "return" the value of an async call synchronously, since it is a promise.
}
or:
async function asyncParentFunction( callback ) {
var value = await some_async_call();
if (value)
callback( value );
return value;
}
however, this transforms the parent-function into an async function as well, which means the immediate return value of that function... is a promise as well.
Long story short:
You either use callbacks to flow through your asynchronous functions, or promises, or async/await
callbacks
function doStuff(callback) {
// do asynchronous stuff
var result = 100;
callback(result); // once you're done with stuff
}
doStuff( function(data) { console.log('Im done!', data); } );
promises
function doStuff() {
return new Promise(function(resolve, reject) {
// do asynchronous stuff
var result = 100;
resolve(result);
});
}
doStuff.then(function(data) { console.log('Im done!', data); });
async/await
function doStuff() {
return new Promise(function(resolve, reject) {
// do asynchronous stuff
var result = 100;
resolve(result);
});
}
(async function() { // async/await only works in async functions.
var data = await doStuff();
console.log('Im done!', data);
})();
as you can see: promises and async/await use the same mechanism and are really worth reading into.
a practical example of the difference between the three:
callbacks
function fetchUserWithPosts(userId, callback) {
fetchUser(userId, function(user) {
fetchPostsByUserId(userId, function(posts) {
callback({
user: user,
posts: posts
});
});
});
}
promises
function fetchUserWithPosts(userId) {
return Promise.all([
fetchUser(userId),
fetchPostsByUserId(userId)
]).then(function(result) {
return {
user: result[0],
posts: result[1]
};
});
}
async/await
async function fetchUserWithPosts(userId) {
return {
user: await fetchUser(userId),
posts: await fetchPostsByUserId(userId);
};
}
You are correct, undefined will be returned. You execute your logic after asynchronous operation you should pass your callback into that function. You are trying to use code in synchronous manner and async/await comes to the rescue. Assuming that some_async_call returns Promise you can write:
async function f(callback) {
var value = await some_async_call();
if (value) {
callback(value);
}
return value;
}
In this case your function will return Promise of value and also will be asynchronous. Read more here.
And even more you don't need to pass a callback. You can await your function in client code and execute callback from there.
Regarding branching, the only way you can branch without using async/await is to make some_async_call accept a callback that accepts the value as parameter:
function f(callback) {
some_async_call(function(value) {
if (value) {
callback(value);
}
});
}
And to reiterate once again there is no way to return a value from async method except Promise. Or Observable in RxJS.