Why async returns promise in JS [duplicate] - javascript

I read that async functions marked by the async keyword implicitly return a promise:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
but that is not coherent...assuming doSomethingAsync() returns a promise, and the await keyword will return the value from the promise, not the promise itsef, then my getVal function should return that value, not an implicit promise.
So what exactly is the case? Do functions marked by the async keyword implicitly return promises or do we control what they return?
Perhaps if we don't explicitly return something, then they implicitly return a promise...?
To be more clear, there is a difference between the above and
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise.
I don't have a big problem with it, but it does defy normal JS.

The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
Same thing even if there's no return! (Promise { undefined } is returned)
async function increment(num) {}
Same thing even if there's an await.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Promises auto-unwrap, so if you do return a promise for a value from within an async function, you will receive a promise for the value (not a promise for a promise for the value).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
In my synopsis the behavior is indeed inconsistent with traditional
return statements. It appears that when you explicitly return a
non-promise value from an async function, it will force wrap it in a
promise. I don't have a big problem with it, but it does defy normal
JS.
ES6 has functions which don't return exactly the same value as the return. These functions are called generators.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);

Yes, an async function will always return a promise.
According to the tc39 spec, an async function desugars to a generator which yields Promises.
Specifically:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Where spawn "is a call to the following algorithm":
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}

Your question is: If I create an async function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.
Suppose doSomethingAsync is a function that returns a promise. Then
async function getVal(){
return await doSomethingAsync();
}
is exactly the same as
async function getVal(){
return doSomethingAsync();
}
You probably are thinking "WTF, how can these be the same?" and you are right. The async will magically wrap a value with a Promise if necessary.
Even stranger, the doSomethingAsync can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.

Just add await before your function when you call it :
var ret = await getVal();
console.log(ret);

async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield
I think the syntax (I am not 100% sure) is
async function* getVal() {...}
ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this
db.exec(function*(connection) {
if (params.passwd1 === '') {
let sql = 'UPDATE People SET UserName = #username WHERE ClinicianID = #clinicianid';
let request = connection.request(sql);
request.addParameter('username',db.TYPES.VarChar,params.username);
request.addParameter('clinicianid',db.TYPES.Int,uid);
yield connection.execSql();
} else {
if (!/^\S{4,}$/.test(params.passwd1)) {
response.end(JSON.stringify(
{status: false, passwd1: false,passwd2: true}
));
return;
}
let request = connection.request('SetPassword');
request.addParameter('userID',db.TYPES.Int,uid);
request.addParameter('username',db.TYPES.NVarChar,params.username);
request.addParameter('password',db.TYPES.VarChar,params.passwd1);
yield connection.callProcedure();
}
response.end(JSON.stringify({status: true}));
}).catch(err => {
logger('database',err.message);
response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});
Notice how I just program it like normal synchronous particularly at
yield connection.execSql and at yield connection.callProcedure
The db.exec function is a fairly typical Promise based generator
exec(generator) {
var self = this;
var it;
return new Promise((accept,reject) => {
var myConnection;
var onResult = lastPromiseResult => {
var obj = it.next(lastPromiseResult);
if (!obj.done) {
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
}
accept(obj.value);
}
};
self._connection().then(connection => {
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
reject(error);
});
});
}

Related

Node.js I keep getting Promise { <pending> } when I make an API call then try to save results to variable and then log to console [duplicate]

I read that async functions marked by the async keyword implicitly return a promise:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
but that is not coherent...assuming doSomethingAsync() returns a promise, and the await keyword will return the value from the promise, not the promise itsef, then my getVal function should return that value, not an implicit promise.
So what exactly is the case? Do functions marked by the async keyword implicitly return promises or do we control what they return?
Perhaps if we don't explicitly return something, then they implicitly return a promise...?
To be more clear, there is a difference between the above and
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise.
I don't have a big problem with it, but it does defy normal JS.
The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
Same thing even if there's no return! (Promise { undefined } is returned)
async function increment(num) {}
Same thing even if there's an await.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Promises auto-unwrap, so if you do return a promise for a value from within an async function, you will receive a promise for the value (not a promise for a promise for the value).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
In my synopsis the behavior is indeed inconsistent with traditional
return statements. It appears that when you explicitly return a
non-promise value from an async function, it will force wrap it in a
promise. I don't have a big problem with it, but it does defy normal
JS.
ES6 has functions which don't return exactly the same value as the return. These functions are called generators.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
Yes, an async function will always return a promise.
According to the tc39 spec, an async function desugars to a generator which yields Promises.
Specifically:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Where spawn "is a call to the following algorithm":
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
Your question is: If I create an async function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.
Suppose doSomethingAsync is a function that returns a promise. Then
async function getVal(){
return await doSomethingAsync();
}
is exactly the same as
async function getVal(){
return doSomethingAsync();
}
You probably are thinking "WTF, how can these be the same?" and you are right. The async will magically wrap a value with a Promise if necessary.
Even stranger, the doSomethingAsync can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.
Just add await before your function when you call it :
var ret = await getVal();
console.log(ret);
async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield
I think the syntax (I am not 100% sure) is
async function* getVal() {...}
ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this
db.exec(function*(connection) {
if (params.passwd1 === '') {
let sql = 'UPDATE People SET UserName = #username WHERE ClinicianID = #clinicianid';
let request = connection.request(sql);
request.addParameter('username',db.TYPES.VarChar,params.username);
request.addParameter('clinicianid',db.TYPES.Int,uid);
yield connection.execSql();
} else {
if (!/^\S{4,}$/.test(params.passwd1)) {
response.end(JSON.stringify(
{status: false, passwd1: false,passwd2: true}
));
return;
}
let request = connection.request('SetPassword');
request.addParameter('userID',db.TYPES.Int,uid);
request.addParameter('username',db.TYPES.NVarChar,params.username);
request.addParameter('password',db.TYPES.VarChar,params.passwd1);
yield connection.callProcedure();
}
response.end(JSON.stringify({status: true}));
}).catch(err => {
logger('database',err.message);
response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});
Notice how I just program it like normal synchronous particularly at
yield connection.execSql and at yield connection.callProcedure
The db.exec function is a fairly typical Promise based generator
exec(generator) {
var self = this;
var it;
return new Promise((accept,reject) => {
var myConnection;
var onResult = lastPromiseResult => {
var obj = it.next(lastPromiseResult);
if (!obj.done) {
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
}
accept(obj.value);
}
};
self._connection().then(connection => {
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
reject(error);
});
});
}

Does async tag wrap a JavaScript function with a Promise?

So I understand that "async" ensures that a function will return a Promise, and if it doesn't then it wraps it in a promise.
My question is, if the function is already returning a Promise, does "async" wrap it in another Promise?
async function, return non-Promise:
async function foo() {
return 5;
}
console.log(foo()) // Promise { 5 }
regular function, return Promise:
function foo() {
return Promise.resolve(5);
}
console.log(foo()) // Promise { 5 }
async function, return Promise:
async function foo() {
return Promise.resolve(5);
}
console.log(foo()) // Promise { <pending> }
Why does the last one return "Promise { pending }" ? My intuition tells me the redundant "async" tag is wrapping the already returned Promise with another Promise. Is this correct?
If an async function returns a Promise, then the Promise returned by that function will resolve to the same value as the original Promise. This can be seen with a simple example:
async function foo() {
return Promise.resolve(42);
}
console.log(await foo()); // "42", not "Promise { 42 }"
So in most normal situations, we can simply imagine that the Promise returned by the code inside the async function body is returned without being touched. But as you've stumbled across, even though the Promise returned by an async function will resolve to the same value as a Promise returned by the code, the actual Promise object is not necessarily the same:
let p1;
async function foo() {
p1 = Promise.resolve(42);
return p1;
}
let p2 = foo();
console.log('p1 === p2 ?', p1 === p2); // "false" (!)
So we can see that the Promise object returned by the function invocation is actually different from the Promise object that the function body returned. No matter, though, it will give the same result when we await it (or use Promise.then()):
let p1;
async function foo() {
p1 = Promise.resolve(42);
return p1;
}
let p2 = foo();
console.log(await p1); // '42'
console.log(await p2); // also '42'
(Note that to run these examples in e.g. a node repl shell, you'll need to wrap them like:
async function main() {
/* code using async / await here */
}
main();
You need to call your last function as:
foo.then(function(r){console.log(r)});
The reason being, an async function needs to return a promise. A promise will log pending until the result is resolved. To capture the promise, you must call "then".
Here is a link for more info about then:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
Here is a link for more info about async functinos:
https://fmpapidev.holstein.ca/swagger/index.html
Now I'm not certain what the native implementation of async/ await is for modern node apps but if you take a look at what Babel generates when it transpiles to node 6
Take this simple async function:
async function fooAsync() {
return 1;
}
Babel transforms this code to look like this:
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function fooAsync() {
return _fooAsync.apply(this, arguments);
}
function _fooAsync() {
_fooAsync = _asyncToGenerator(function* () {
return 1;
});
return _fooAsync.apply(this, arguments);
}
You can see the transformation of your async method and the state machine it generates. The interesting part is that the generator, when executed, return a new Promise(). So to answer your question, just having the keyword async in your function, would make it return a Promise. This can also be seen in Typescript where the compiler will moan if you have an async method and you don't specify a return type of Promise<T>

JavaScript Async/Await console.log() on array returns empty

Hello Stack Overflow community,
I come to you with a problem related to JS async/await. I am trying to call an async function and then log the array to where the async function pushes the results to the console. If I call it like so directly in the console:
console.log(Page.data) - I can see that it has results in it, but if it is called on click of a button it logs an empty array.
// It is a nested object so do not worry if you don't exactly understand where Page.data comes from
Page.data = []
async function f1() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function f2() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function f3() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function load(loader) {
let fn = async function() {};
if(condition1) fn = f1;
else if(condition2) fn = f2;
else fn = f3;
// This is the line that makes me problems
// According to documentation async functions return a promise
// So why would the array in the case be empty?
// Since I am telling it to display after the function is done
await fn(loader).then(console.log(Page.data))
}
This is just a template of my code and logic. I hope that you can understand where I am going.
Your help will be much appreciated.
The await expression causes async function execution to pause until a Promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise.
For instance (this is an MDN example with some added comments):
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
// note that here, you are "awaiting" the RESOLVED RESULT of the promise.
// there is no need to "then" it.
var x = await resolveAfter2Seconds(10);
// the promise has now already returned a rejection or the resolved value.
console.log(x); // 10
}
f1();
So you would "await" your function, which would hold up the execution until the promise either resolves or rejects. After that line, you would run your console.log, and it would log as expected. Short answer, "remove the then".
I should add, if the result of the "awaited" function is not a promise, it is converted to a promise (so technically, there is no need to return a promise, it'll wrap up your returned value for you).
the problem is that you can use then with await for the same method, lets check some examples provided by MDN:
this is a working Promise using async/await:
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!");
}, 250)
})
const functionCaller = async() => {
const result = await myFirstPromise
console.log("the result: ", result);
}
functionCaller();
what you are trying is:
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!");
}, 250)
})
const functionCaller = async() => {
// you are not returning anything here... actually you are not doing anything with the response. despite it shows something, it is not sending any response
await myFirstPromise.then(console.log("something happened"))
}
// then this function doesn't really get a value.
functionCaller();
so what you need to do in your load call, is to change it like this:
async function load(loader) {
let fn = async function() {};
if(condition1) fn = f1;
else if(condition2) fn = f2;
else fn = f3;
return await fn(loader)
}

Change the value of variable with the resolve data of promise

How to change the value of data inside the asyncCall() and set it to the resolve value of the promise which is b.
What I wanted is that the asyncCall() will return b.
But what happen is that asyncCall() returns a Promise object.
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
asyncCall();
Use IIFE
Making the function async will automatically have it return a Promise. You will either have to await it, or use .then to access the resolved value. IIFE stands for "Immediately Invoked Function Expression" – Tim VN
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
(async function() {
console.log(await asyncCall())
})()
An async function will always return a Promise (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#Return_value).
If you put a console.log(result) statement in the asyncCall() function body, you will realize that the value is actually resolved right there and can be used as you'd expect it. But as documented, the return value of an async function will always be "promisified", so you'd have to "await" that function call too.
To do that at the top (global) level, you can either use an IIFE (Immediately Invoked Function Expression):
(async () => console.log(await asyncCall()))();
or fall back to classical callback functions using Promise.then():
asyncCall().then(value => console.log(value));
Some browsers also support top level await expressions:
await asyncCall();
declaring function with async will return classic Promise.
so you have to use callbacks or await.
async function asyncCall() will return Promise not the result you want to.
asyncCall().then((data) => console.log('in data is your result'));
Async functions return a promise itself:
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
return resolve(data);
});
}
async function asyncCall() {
const result = await resolveAfter2Seconds("b");
return result;
}
asyncCall().then(
data => console.log(data)
);

Return from a promise then()

I have got a javascript code like this:
function justTesting() {
promise.then(function(output) {
return output + 1;
});
}
var test = justTesting();
I have got always an undefined value for the var test. I think that it is because the promises are not resolved yet..there is a way to return a value from a promise?
When you return something from a then() callback, it's a bit magic. If you return a value, the next then() is called with that value. However, if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails).
Source: https://web.dev/promises/#queuing-asynchronous-actions
To use a promise, you have to either call a function that creates a promise or you have to create one yourself. You don't really describe what problem you're really trying to solve, but here's how you would create a promise yourself:
function justTesting(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
Or, if you already have a function that returns a promise, you can use that function and return its promise:
// function that returns a promise
function delay(t) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, t);
});
}
function justTesting(input) {
return delay(100).then(function() {
return input + 10;
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
What I have done here is that I have returned a promise from the justTesting function. You can then get the result when the function is resolved.
// new answer
function justTesting() {
return new Promise((resolve, reject) => {
if (true) {
return resolve("testing");
} else {
return reject("promise failed");
}
});
}
justTesting()
.then(res => {
let test = res;
// do something with the output :)
})
.catch(err => {
console.log(err);
});
Hope this helps!
// old answer
function justTesting() {
return promise.then(function(output) {
return output + 1;
});
}
justTesting().then((res) => {
var test = res;
// do something with the output :)
}
I prefer to use "await" command and async functions to get rid of confusions of promises,
In this case I would write an asynchronous function first,
this will be used instead of the anonymous function called under "promise.then" part of this question :
async function SubFunction(output){
// Call to database , returns a promise, like an Ajax call etc :
const response = await axios.get( GetApiHost() + '/api/some_endpoint')
// Return :
return response;
}
and then I would call this function from main function :
async function justTesting() {
const lv_result = await SubFunction(output);
return lv_result + 1;
}
Noting that I returned both main function and sub function to async functions here.
Promises don't "return" values, they pass them to a callback (which you supply with .then()).
It's probably trying to say that you're supposed to do resolve(someObject); inside the promise implementation.
Then in your then code you can reference someObject to do what you want.
I think what the original poster wants is to return an unwrapped value from a promise without actually returning another promise. Unless proven otherwise, I'm afraid this is not possible outside of a then() or async/await context. You always get a promise no matter what.
You need to make use of reference data type like array or object.
function foo(u,n){
let result = [];
const userBrands = new Promise((res, rej)=> {
res(['brand 1', 'brand 3']);
})
userBrands.then((ub)=>{
return new Promise((res, rej) =>{
res([...ub, 'brand 4', 'brand 5']);
})
}).then(response => {
return result.push(...response);
});
return result;
};
foo();
You cannot return value after resolving promise. Instead call another function when promise is resolved:
function justTesting() {
promise.then(function(output) {
// instead of return call another function
afterResolve(output + 1);
});
}
function afterResolve(result) {
// do something with result
}
var test = justTesting();

Categories

Resources