Async await issue on nodejs - javascript

I'm learning to use async/await and this is quite confused to me. As I know, async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
async function foo() {
setTimeout(() => {
throw new Error('error');
}, 5000);
}
async function test() {
try {
await foo();
} catch (err) {
console.log(err);
}
console.log('not reached');
}
test();
Expected output: log the error after 5 secs, then log "not reach".
What actually happened: "not reach" gets logged right after I start the script, then the error gets logged after 5 seconds.
Attempts: the following code does exactly what I want, but I don't know what's the difference between those code.
Environment: nodejs 16.14.2
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('foo'));
}, 5000);
});
}
async function test() {
try {
await foo();
} catch (err) {
console.log(err);
}
console.log('not reached');
}
test();
Thanks a lot!

foo needs to actually resolve
Your example doesn't work because foo doesn't actually care about the timeout. It just starts the timeout then returns immediately. What you need to do is make foo resolve when the timeout fires, which actually requires you to construct a Promise explicitly.
async function foo() {
return new Promise(resolve => {
setTimeout(resolve, 5000)
})
}
Since you return a Promise, you could technically not declare foo as async, but it doesn't matter, and (I think) it's still helpful for other developers to see that the function returns a Promise without having to look through the implementation.

In your second example, foo returns a promise, setTimeout needs to produce a promise for it to work in your example.
For example
async function foo() {
// promise returned
return new Promise(resolve => {
setTimeout(() => { resolve() } , 5000)
})
}

Related

why it didn't catch the rejected promise? [duplicate]

This question already has answers here:
How to .catch a Promise.reject
(4 answers)
How to use try/catch, promise catch and async function correctly?
(1 answer)
Closed 7 months ago.
I was wondering why the try-catch block couldn't catch the promise rejected from foo.
Frustrated, need help. Thanks in advance.
function addTask(task) {
setTimeout(() => {
task.resolver()
}, 1000)
}
function foo() {
return new Promise((resolve, reject) => {
const task = {
resolver: function() {
reject('task failed')
}
}
addTask(task)
})
}
function test() {
try {
foo()
} catch (e) {
console.error(e)
}
}
// Uncaught (in promise) task failed
test()
It's the same reason that if you had:
const result = foo();
Then you would have a promise stored in result and not the settled value of the promise.
The asynchronous code is started, then the calling function continues.
Sometime later the promise is rejected, but by then it is too late for the code in test() to catch it.
If you had awaited foo(), which would require that test() be async, then it would be caught.
Otherwise you could need to use foo().catch(...).
Promises are asynchronous but you are not awaiting. It means code continues. So you have to await or you have to use then().catch(). Something like this:
function addTask(task) {
setTimeout(() => {
task.resolver()
}, 1000)
}
function foo() {
return new Promise((resolve, reject) => {
const task = {
resolver: function() {
reject('task failed')
}
}
addTask(task)
})
}
function test() {
foo().then(console.log).catch(console.error);
}
// Uncaught (in promise) task failed
test()
To simplify your example:
function foo() {
return new Promise((resolve, reject) => setTimeout(reject, 1000))
}
function test() {
try {
foo()
} catch (e) {
console.error("Error");
return;
}
console.log("OK!");
}
test()
will print "OK!" indeed have Node.js raise an UnhandledPromiseRejection, as that foo() invocation is just "throwing away" the promise result value. The catch() would only catch synchronous exceptions, not promise rejections.
Turning the function into async function test() and awaiting on foo() will correctly output Error and no unhandled rejection.
Add await before foo() call and async before test function declaration
like below
setTimeout(() => {
task.resolver()
}, 1000)
}
function foo() {
return new Promise((resolve, reject) => {
const task = {
resolver: function() {
reject('task failed')
}
}
addTask(task)
})
}
async function test() {
try {
await foo()
} catch (e) {
console.error(e)
}
}
// Uncaught (in promise) task failed
test()`

javascript ES6 / how to correctly chain Promises and implement handling

I have written a class to capture a microservice accessed vi https. Several calls have been implemented in asynchronous methods which all work fine by themselves (here: step1(), step2(), step3()).
However I want to call a few of those in succession (run()) to implement certain workflows.
What I can not manage so far is that the stepX methods get called after another. Also I want to call run() and get a promise back so I can .then() when all is done. Also I want to implement some error handling there to catch all errors that might occur during the chain.
Here's a class that reduces my problems to the core:
class Foo {
run() {
return this.step1()
.then(() => this.step2())
.then(() => this.step3())
}
step1() {
console.log('1')
return new Promise(function(resolve) {
setTimeout(function(){console.log('2')}, 500)
});
}
step2() {
console.log('3')
return new Promise(function(resolve) {
setTimeout(function(){console.log('4')}, 500)
});
}
step3() {
console.log('5')
return new Promise(function(resolve) {
setTimeout(function(){console.log('6')}, 500)
});
}
}
let bar = new Foo();
bar.run()
.then(console.log('7')) // react on run() finishing successfully
.catch(err => console.log('err:', err)) // global error handling
I expected this to output the numbers 1 to 7 in correct order. However the current output is
1
7
2
Thank you for any help!
Christian
There were a couple problems in your code:
You weren't resolving the promises in step1(), step2() and step3().
.then(console.log('7')) was calling the console.log() immediately and not waiting for the promise. You must pass a callback to .then().
With these two issues fixed, here's the resulting code which you can run in the snippet and see the desired output:
class Foo {
run() {
return this.step1()
.then(() => this.step2())
.then(() => this.step3())
}
step1() {
console.log('1')
return new Promise(function(resolve) {
setTimeout(function() {
console.log('2');
resolve();
}, 500)
});
}
step2() {
console.log('3')
return new Promise(function(resolve) {
setTimeout(function() {
console.log('4');
resolve();
}, 500)
});
}
step3() {
console.log('5')
return new Promise(function(resolve) {
setTimeout(function() {
console.log('6');
resolve();
}, 500)
});
}
}
let bar = new Foo();
bar.run()
.then(() => console.log('7')) // react on run() finishing successfully
.catch(err => console.log('err:', err)) // global error handling
This generates the output:
1
2
3
4
5
6
7
You can use async-await approach with try-catch-finally to handle the resolve & reject cases in promises.
I'm writing tweaking the code a little bit to write the example by using a static function. you can use it as you normally would.
class Foo {
static async run() {
let response = {status:false, result:'Failed' }
try{
const step1_response = await step1();
const step2_response = await step2();
response.status = true;
response.result = {step1_response, step2_response};
} catch(error) {
console.log(error)
} finally {
return response;
}
}
}

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!

promise then is not the function error for Node Promise

I am using async/await to return the Promise , to use it as promoise in node script. When I am trying to make use of the return value as Promise , its giving a error a.then is not a function
here is the sample code
function test () {
//do something .......
//....
return global.Promise;
}
(async ()=> {
let a = await test();
a.then(()=> { console.log('good ')}, (err)=> { console.log()});
})();
The Promise constructor function isn't a promise, it is a tool to make promises with.
Even if it was a promise, since you are awaiting the return value of test, it would have been resolved into a value before you try to call then on it. (The point of await is that it replaces the use of then() callbacks).
You can await a function that returns a promise like this:
function test() {
return new Promise((resolve, reject) => {
if (true) {
reject("Custom error message");
}
setTimeout(() => {
resolve(56)
}, 200);
})
}
async function main() {
try {
const a = await test();
console.log(a)
} catch (e) { // this handles the "reject"
console.log(e);
}
}
main();
If you change the true to false you can test the "resolve" case.
await retrieves the resolved value from a Promise
let a = await test(); // `a` is no longer a Promise
I've put together two ways of retrieving values from a Promise
using await
(async () => {
try {
let a = await test();
console.log('Good', a);
} catch(err) {
console.log(err);
}
})();
using .then()
test().then(a => {
console.log('Good', a);
}).catch(err => {
console.log(err);
});
Please note that, the async arrow function is removed because there is no await needed.

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.

Categories