将Async函数传递给Node.js Express.js路由器

时间:2017-06-28 22:15:40

标签: javascript node.js express async-await

这似乎是一个简单的谷歌,但我似乎无法找到答案......

您可以将ES7异步功能传递给Express路由器吗?

示例:

var express = require('express');
var app = express();

app.get('/', async function(req, res){
  // some await stuff
  res.send('hello world');
});

如果没有,你能指出我如何处理这个问题的正确方向ES7风格?或者我只需要使用承诺?

谢谢!

6 个答案:

答案 0 :(得分:9)

可能是您没有找到结果,因为async/await ES7 而不是ES6功能,它在节点> = 7.6中可用。

您的代码将在节点中运行。 我测试了以下代码

var express = require('express');
var app = express();

async function wait (ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms)
  });
}

app.get('/', async function(req, res){
  console.log('before wait', new Date());
  await wait(5 * 1000);
  console.log('after wait', new Date())
  res.send('hello world');
});

app.listen(3000, err => console.log(err ? "Error listening" : "Listening"))

MacJamal:messialltimegoals dev$ node test.js 
Listening undefined
before wait 2017-06-28T22:32:34.829Z
after wait 2017-06-28T22:32:39.852Z
^C

基本上,你得到它,你必须async一个函数,以便await在其代码中的承诺。 这在节点LTS v6中不受支持,因此可能使用babel来转换代码。 希望这会有所帮助。

答案 1 :(得分:3)

这有点奏效,但不是真的

虽然看起来可行,但它会停止处理异步函数中引发的错误,结果,如果未处理错误,则服务器将永远不会响应,客户端会一直等待直到超时。

正确的行为应该是使用 500 状态码进行响应。


解决方案

express-promise-router

const router = require('express-promise-router')();

// Use it like a normal router, it will handle async functions

express-asyncify

const asyncify = require('express-asyncify')

要修复在app对象中设置的路由

var app = express();替换为

var app = asyncify(express());

要修复在router个对象中设置的路由

var router = express.Router();替换为

var router = asyncify(express.Router());

注意

您只需要在直接设置路径的对象中应用asyncify函数

https://www.npmjs.com/package/express-asyncify

答案 2 :(得分:2)

我认为你不能直接这样做,因为没有捕获异常,如果抛出异常,函数将不会返回。本文介绍如何创建包装函数以使其工作:http://thecodebarbarian.com/using-async-await-with-mocha-express-and-mongoose.html

我没有尝试过,但最近正在调查此事。

答案 3 :(得分:0)

使用express-promise-router

const express = require('express');
const Router = require('express-promise-router');
const router = new Router();   
const mysql = require('mysql2');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'myusername',
  password: 'mypassword',
  database: 'mydb',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
}).promise();

router.get('/some_path', async function(req, res, next) {
  const [rows, ] = await pool.execute(
    'SELECT * ' +
    'FROM mytable ',
    []
  );

  res.json(rows);
});

module.exports = router;

(以上是在express-promise-router上使用mysql2的promise接口的示例。)

答案 4 :(得分:0)

要处理快速路由中的异步请求,请使用try catch,它可以帮助您尝试功能中的任何错误并加以捕获。 try{await stuff} catch{err}

答案 5 :(得分:0)

Express 5 会自动为您处理 async 个错误

https://expressjs.com/en/guide/error-handling.html 目前明确表示:

<块引用>

从 Express 5 开始,返回 Promise 的路由处理程序和中间件将在拒绝或抛出错误时自动调用 next(value)。例如:

app.get('/user/:id', async function (req, res, next) {
 var user = await getUserById(req.params.id)
 res.send(user)
})

如果 getUserById 抛出错误或拒绝,next 将使用抛出的错误或拒绝的值调用。如果没有提供拒绝值,next 将使用 Express 路由器提供的默认 Error 对象调用。

我们可以进行如下测试:

const assert = require('assert')
const http = require('http')

const express = require('express')

const app = express()
app.get('/error', async (req, res) => {
  throw 'my error'
})

const server = app.listen(3000, () => {
  // Test it.
  function test(path, method, status, body) {
    const options = {
      hostname: 'localhost',
      port: server.address().port,
      path: path,
      method: method,
    }
    http.request(options, res => {
      console.error(res.statusCode);
      assert(res.statusCode === status);
    }).end()
  }
  test('/error', 'GET', 500)
})

express@5.0.0-alpha.8 上的终端输出是预期的:

500
Error: my error
    at /home/ciro/test/express5/main.js:10:9
    at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
    at next (/home/ciro/test/node_modules/router/lib/route.js:144:13)
    at Route.dispatch (/home/ciro/test/node_modules/router/lib/route.js:109:3)
    at handle (/home/ciro/test/node_modules/router/index.js:515:11)
    at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
    at /home/ciro/test/node_modules/router/index.js:291:22
    at Function.process_params (/home/ciro/test/node_modules/router/index.js:349:12)
    at next (/home/ciro/test/node_modules/router/index.js:285:10)
    at Function.handle (/home/ciro/test/node_modules/router/index.js:184:3)

如果您在浏览器上访问它,您将看到一个显示 my error 的 HTML 页面。

如果您在 express@4.17.1 上运行完全相同的代码,您只会在终端上看到:

UnhandledPromiseRejectionWarning: my error

但不是 500my error。这是因为请求永远挂起。如果您尝试在浏览器中打开它,您会更清楚地看到它。

TODO:如何让它也显示堆栈跟踪,而不仅仅是my errorGetting the stack trace in a custom error handler in Express?

Express 4 解决方案

Express 4 最简单的解决方案是将每条路线包装在 try/catch 中,如下所示:

app.get('/error', async (req, res, next) => {
  try {
    throw new Error('my error'
    res.send('never returned')
  } catch(error) {
    next(error);
  }
})

产生与 Express 5 相同的正确行为。

您还可以使用以下讨论的一些方法进一步解决这个问题:express.js async router and error handling

在 Node.js v14.16.0 上测试。