Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use async/await in express 5? #4256

Closed
vipkouyu opened this issue Apr 26, 2020 · 3 comments
Closed

How to use async/await in express 5? #4256

vipkouyu opened this issue Apr 26, 2020 · 3 comments
Labels

Comments

@vipkouyu
Copy link

Here is my express 4.X code as follows:

router.post('/sign-in/do',function(req,res){

	db.query('sql08',[req.body.email,req.body.pswd]).then(function(result){
		console.log('result:',result);
		if (result.length > 0) {
			req.login(result[0].id,function(err){
				if(err){
					return res.send('19');
				}else{
					return res.send('99');
				}
			})
		} else {
			db.query('sql25',[req.body.email,t]).then(function(result){
				if(result.length > 0){
					var count=result[0].count+1;
					db.query('str26',[++result[0].count,req.body.email,t]).then(function(data){
					})
				}else{
					var row={};
					db.query('sql27',row).then(function(data){
					})
				}
			})
			return res.send('10');
		}
	});	
});

I want to use async/await in express 5, but i don't find a example anywhere. As the following code, the mysql part has no problem(I have used bluebird to return a promise in mysql.js) ,but the other part code i think have a lot problem.

1、Is the right way to use async function?
2、In the async function, you can't use .then function(req.login)?
3、How to catch errors?

router.post('/sign-in/do',async function(req,res){

	let result =await db.query('sql08',[req.body.email,req.body.pswd])
	console.log('result:',result);
	if (result.length > 0) {
		req.login(result[0].id,function(err){
			if(err){
				return res.send('19');
			}else{
				return res.send('99');
			}
		})
	} else {
		await db.query('sql25',[req.body.email,t])
		if(result.length > 0){
			var count=result[0].count+1;
			await db.query('sql26',[++result[0].count,req.body.email,t])
			
		}else{
			var row={};
			await db.query('sql27',row)
		}
	})
	return res.send('10');
});
@jonchurch
Copy link
Member

jonchurch commented Apr 26, 2020

Hey there, I won't comment on the "right way to use async/await" outside the context of Express v5, as you're best served by reading about async/await itself in other places.

But I am happy to talk about it in the context of Express 5.

There is one main difference between v4 and v5 when it comes to async/await and promises in general. In v5, if you return a promise from a response handler (or middleware), if that promise rejects and is not handled elsewhere, then Express will handle the error. It handles the rejection by passing the rejection reason to next for you.

Look at these examples, they are functionally equivalent:

v4 example:

app.get('/test', function(req, res, next) {
  return db().then(result =>{
    // handle successful result
  }).catch(err => {
    // handle rejected promise
    next(err)
  })
})

v5 example:

app.get('/test', async function(req, res, next) {
  const result = await db()
    // handle successful result
})

Both return a promise directly from the handler function. In the v4 example, the return is explicit (and we are assuming db returns a promise), in the v5 example w/ async/await, the async function implicitly returns a promise.

In the v4 example, we must manually catch the error and pass it to next. In the v5 example, it is not strictly necessary as Express will do it behind the scenes.

The point of the example is to show the different behavior between v4 and v5.

To answer 2, async functions can indeed still use .then with promises, that is a fact that relates to async/await and not Express, however, so I will not go into more detail there.

For 3, the simple answer is to use try/catch blocks, and decide how to handle errors yourself within the function. That is not strictly necessary, because if any single one of the await calls rejects, the function will stop executing, and the overall promise returned by the async function will reject, at which point Express will pass that error to next, which triggers the same behavior as v4 where the error will be forwarded to the next error handler.

In the example v4 code you posted, you are not explicitly handling any errors currently (besides the error returned from req.login). In the v5 code you posted, if any of the awaited calls reject, execution will be stopped and the error forwarded to next. That is different from your v4 code, where any rejected promises will have their errors swallowed, and not handled.

There are some subtle control flow differences between your v4 and v5 code, due to the use of await. Specifically the response in the else block return res.send('10');, will not be sent until the awaited db calls complete. In your v4 code, the response is sent before the db calls complete because the response is happening outside of the .then handler. But that is async/await specific and not related to Express.

@vipkouyu
Copy link
Author

@jonchurch Thank you very much.

I asked this question because my test app often crashes and doesn't respond the connection. At first, I thought the reason was express didn't support async and await very well. After nearly three weeks of exploration, I knew that the reason was that there was no error handling in my code and cause the server crash.

Your error handling differences between V4 and V5 are really good articles, and they benefit a lot, Thank you very much.

@jonchurch
Copy link
Member

@vipkouyu I'm happy I could help, if you have any other questions feel free to ask 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants