About 'pending' and 'fulfilled' promise of javascript async function - javascript

async function pending() {
return new Promise((resolve, reject) => { resolve(1) });
}
async function fulfilled() {
return 1;
}
function promiseState(p) {
return Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
}
promiseState(pending()).then(s => { console.log(s); }); // pending
promiseState(fulfilled()).then(s => { console.log(s); }); // fulfilled
pending().then(r => { console.log(r); }); // 1
fulfilled().then(r => { console.log(r); }); // 1
What's different?
When should I use 'return new Promise(...' in async function? and Why?

It's the same as the difference between
function pending() {
return Promise.resolve(Promise.resolve(1));
}
and
function fulfilled() {
return Promise.resolve(1);
}
The former just takes one promise tick longer to settle.
When should I use 'return new Promise(...' in async function?
Probably never. See How to turn this callback into a promise using async/await? and What is the benefit of prepending async to a function that returns a promise?.

You should not construct Promises explicitly inside another Promise or async function, thats the promise constructor antipattern. It just adds additional overhead and you get no benefit whatsoever. If you somewhen really need the Promise constructor (for wrapping a callback API), then the surounding function should not be async, just return the promise.

Related

Can someone explain pls why the Promise returns pending in the first function, but resolved in the other two?

Can someone explain pls why the Promise returns pending in the first function, but resolved in the other two? When i read MDN it states that just using the word async wont make the code inside asynchronous (we need to use the word await as well). Also, I return the promise explicitly, since I use resolve() (which should return fulfilled promise as in two other functions, yet it returns Pending in the first function). I provided the code below.
const testFunc = async() => {
return new Promise((resolve,reject)=> {
resolve()
})
}
const testFunc2 = () => {
return new Promise((resolve,reject)=> {
resolve()
})
}
const testFunc3 = () => {
return new Promise((resolve,reject)=> {
resolve()
})
}
testFunc().then(()=> console.log("Hello")).then(()=> console.log("there")).then(()=> console.log("Obi One"))
testFunc2().then(()=> console.log(1)).then(()=> console.log(2)).then(()=> console.log(3))
testFunc3().then(()=> console.log(4)).then(()=> console.log(5)).then(()=> console.log(6))
console.log(testFunc())
console.log(testFunc2())
console.log(testFunc3())
// Results in the console:
// Promise {<pending>}
// Promise {<fulfilled>: undefined}
// Promise {<fulfilled>: undefined}
// 1
// 4
// 2
// 5
// Hello
// 3
// 6
// there
Thats because testFunc (the function with async keyword) is equalevent to this:
const testFunc = () => {
return new Promise((resolve,reject)=> {
resolve(new Promise((r) => {
r()
}))
})
}
and not
const testFunc = () => {
return new Promise((resolve,reject)=> {
resolve()
})
}
Using async queues the executer as a microtask.
Read about it here: https://whistlr.info/2021/async-and-tasks/
The key point:
When you write an asynchronous function, you force the caller to use a microtask to read its result. This is the case even if you don't await inside it—it will return a Promise regardless

Trying to understand between new Promise and Async/await

I have a very basic question:
This code
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
gives this output, which is correct:
> "calling"
> "resolved"
This one however:
async function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
It gives instead:
> "calling"
> undefined
From javascript.info:
The word “async” before a function means one simple thing: a function
always returns a promise. Other values are wrapped in a resolved
promise automatically. So, async ensures that the function returns a
promise, and wraps non-promises in it
So there's something I am misunderstanding, isn't the resolveAfter2Seconds returning a promise in both scenarios (the resolveAfter2Seconds in the 2nd scenario has async)? If so why the output in the 2nd scenario?
Its a pretty basic beginner mistake you use return in an callback and expect to recevive something from the parent function
This here:
async function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
}
Can be written to this here:
async function resolveAfter2Seconds() {
setTimeout(function() {
return 'resolved';
}, 2000);
}
And as you can see there is a second function and you return resolved to your callback function. There is actually no way to return this value like you want to, you will need to use Promises like in your first example
Since resolveAfter2Seconds doesnt return anything it will return by default undefined
No return = returns undefined
In the second case, you are not returning anything from the
resolveAfter2Seconds function, the return in the code is for the
callback of the setTimeout, which will not be returned by the
resolveAfter2Seconds function. Hence the undefined.
Both functions are returning a promise, the main differences between the two are when each promise resolves and what each promise resolves to. In your second function resolveAfter2Seconds, you're only returning inside of the setTimeout function, and as a result, you return back to the caller of the setTimeout callback function, not your resolveAfter2Seconds. Rather, your resolveAfter2Seconds doesn't return anything, and so it will implicitly return undefined which gets wrapped within a promise. It is more or less the same as writing:
function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
return Promise.resolve(undefined);
}
function resolveAfter2Seconds() {
setTimeout(() => {
return 'resolved';
}, 2000);
return Promise.resolve(undefined); // returns a promise which resolves with the value of `undefined`
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
The above returns a Promise which resolves immediately with the value of undefined. As a result, you either need to explicitly wrap your setTimeout in a promise and resolve() (like your first resolveAfter2Seconds), or use something like a helper sleep method:
const sleep = n => new Promise(res => setTimeout(res, n));
async function resolveAfter2Seconds() {
await sleep(2000);
return "resolved";
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();

Simple async await question with function returns

I have a simple yet perplexing issue with async functions.
I wish to simply return the value when its ready from the function.
Here is a sample code:
async function test() {
setTimeout(function() {
return 'eeeee';
}, 5000);
}
test().then(x => {
console.log(x)
});
You will get undefined been logged at once.
It's clear that you are trying to write a sleep() async function, but do remember that setTimeout is a sync function calling with a callback function will be executed at a given time, so while you are executing test(), the calling will run to end and return undefined as you have no return statement in the function body, which will be passed to your .then() function.
The right way to do this is to return a Promise that will be resolved after a given time, that will continue the then call.
async function sleep(time){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("echo str")
},time)
})
}
sleep(5000).then((echo) => console.log(echo))
sleep function in short
const sleep = async time => new Promise(resolve=>setTimout(resolve,time))
With Promises
const setTimer = (duration) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done!');
}, duration);
});
return promise;
};
setTimer(2000).then((res) => console.log(res));
An async function has to return a promise. So to fix this, you can wrap your setTimeout function in a new promise like so:
async function test(){
return await new Promise((resolve, reject) => {
setTimeout(function(){
resolve('eeeee');
},5000);
})
}
test().then(x => {
console.log(x)
});
You can learn more about async/await on the MDN docs here. Hope this helps!

JavaScript Async/Await

I'm trying to understand JavaScript async/await. How can I rewrite the below such that the output is "Hi" then "Bye" instead of "Bye" then "Hi":
JSFiddle
sayHi()
.then(sayBye);
async function sayHi() {
await setTimeout(function() {
$("#myOutput").text('hi');
}, 1000);
}
async function sayBye() {
$("#myOutput").text('bye');
}
In order to await setTimeout it needs to be wrapped into Promise. Then with async/await you can flatten your code write it without Promise then API:
(async () => { // await has to be inside async function, anonymous in this case
await sayHi()
sayBye()
})()
async function sayHi() {
return new Promise(function (resolve) {
$("#myOutput").text('hi');
setTimeout(function() {
resolve()
}, 1000)
});
}
async function sayBye() {
$("#myOutput").text('bye');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myOutput"></div>
setTimeout doesn't return a Promise. Create a helper function to wrap it in a Promise and then you can await it.
function delay(fn, t) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(fn());
}, t);
});
}
sayHi()
.then(sayBye);
async function sayHi() {
await delay(() => {
//$("#myOutput").text('hi');
console.log("Hi");
}, 1000);
}
async function sayBye() {
//$("#myOutput").text('bye');
console.log("Bye");
}
Use the Promise way
sayHi()
.then(sayBye);
function sayHi() {
return new Promise(resolve => {
setTimeout(()=> {
$("#myOutput").text('hi'), resolve()
}, 1000);
})
}
async function sayBye() {
$("#myOutput").text('bye');
}
or the sayHi like this:
async function sayHi() {
await new Promise(resolve => {
setTimeout(()=> {
$("#myOutput").text('hi'), resolve()
}, 1000)
})
}
Using async/await is an excellent way to build acynchronous code in a quite controllable way. Promise based async function goes into microtasks depository, which event loop executes before events and methods contained in ordinary DOM refresh/web API depository (setTimeout() for example). However some versions of Opera and Firefox browsers set priority to setTimeout() over microtasks depository. Anyway, you can control order of execution if you combine Promise based function with async/await enabled function. For example:
// create function that returns Promise
let hi = () => {
return new Promise((resolve, reject) => {
setTimeout(_ => {
resolve('Hi '); // after 1500ms function is resolved and returns 'Hi '
}, 1500);
});
}
// create ordinary function that will return 'bye'
let sayBye = () => {
return 'Bye';
}
// create third function that will be async 'enabled',
// so it can use await keyword before Promise based functions
let sayHi = async () => {
let first = await hi(); // we store 'Hi ' into 'first' variable
console.log(first);
let second = sayBye(); // this execution will await until hi() is finished
console.log(second);
}
// execute async enabled function
sayHi();
We can add try / catch block inside sayHi() function for controlling error on promise reject(), but this is out of scope of your question.
Have a nice day!
You cannot use async/await for functions that are not returning Promise
When an async function is called, it returns a Promise. When the async function returns a value, the Promise will be resolved with the returned value. When the async function throws an exception or some value, the Promise will be rejected with the thrown value.
An async function can contain an await expression, that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Usually it is used to handle data that comes from server, because when you have multiple queries it can override previous one and you will handle the wrong one.
Async/await lets you handle exactly data you are awaiting for.

How does an async mocha test resolve without returning a promise or invoking the done callback

I would love to better understand the internals of why the following example works as expected:
describe('async await', () => {
it('resolves without return', async () => {
await asyncOperation();
});
});
function asyncOperation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 123);
});
}
Typically an async mocha test must return a promise (or execute the done callback) but in this example nothing is returned but the mocha test still works. How exactly does this work?
From the async documentation:
The async function declaration defines an asynchronous function, which returns an AsyncFunction object.
Description
When an async function is called, it returns a Promise. When the async function returns a value, the Promise will be resolved with the returned value. When the async function throws an exception or some value, the Promise will be rejected with the thrown value.
This means that in your case, a Promise is returned, that's why your test works.
When you use the async keyword, you are implicitly returning a Promise of whatever type you actually use in the return statement of the function (in this case you aren't returning anything, so this is simply a Promise of nothing, or Promise<void> if you're into TypeScript).
Internally, a function that uses async/await gets unrolled into a number of asynchronous continuations, split at each usage of the await keyword. When the promise you are await-ing completes, the remainder of the function is resumed. It may be instructive to see how transpilers like Babel unroll your code.
This code:
function asyncOperation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 123);
});
}
async () => {
await asyncOperation();
}
is transpiled to plain ES5 as:
"use strict";
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function asyncOperation() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, 123);
});
}
_asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return asyncOperation();
case 2:
case "end":
return _context.stop();
}
}
}, _callee, undefined);
}));
That ugly _asyncToGenerator invocation used to be your beautiful async function. It has been unrolled into explicit continuations (you can try adding more await points and logic to the function and seeing how the transpiled code changes).

Categories