如何等待函数或数据库查询? 然后处理结果并最终将其发回

我有这种情况:

app.get('/', async function (request, response) { await foo(DbConnection).then((result) => console.log("response ready")); }) let foo = async function (DbConnection) { const myQuery = "SELECT * FROM my_table"; DbConnection.query(myQuery, async function(err, results) { console.log("query ready"); await bar(results).then((response) => console.log("bar done")) }) return; // go back to app.get() to send stuff to client } let bar = async function (results) { console.log("inside bar"); await ThirdPartyAPI(result).then((value)) => return value); } 

简述:

  • 我收到来自客户端的GET请求

  • 我调用foo()查询数据库,并在结果上应用函数

  • 我使用第三方API来处理结果,这需要花费时间来完成

  • 我把最后的结果发回给客户

我期待看到:

查询准备好了 – >里面的酒吧 – >酒吧完成 – >响应就绪

但我反而看到:

响应就绪 – >查询就绪 – >里面的酒吧 – >酒吧完成

客户端接收undefined因为没有准备好response.send()

可能是什么问题?

你的代码中的主要问题是你正在混合async/await语法和callback。 只有当你想在这个函数里面做asynchronous调用的结果时才使用async函数。

此外,具体到你的情况,你需要promisify connection.query() – 创build一个承诺。 看到正确的模式与工作代码:

 app.get('/', async (request, response) => { // waiting for the result of foo let result = await foo(); console.log("response ready"); }); let foo = async () => { const myQuery = "SELECT * FROM my_table"; // getting the result of the query let results = await new Promise((resolve, reject) => connection.query(myQuery, (err, results) => { if (err) { reject(err) } else { resolve(results); } })); console.log("query ready"); // call bar and waiting the result let res = await bar(results); console.log("bar done"); // return resolved promise return res; } let bar = (results) => { console.log("inside bar"); // just return a promise, we don't need the result here return ThirdPartyAPI(result); } 

有关使用async/await说明async/await的强大之处在于它可以让你使用同步语言结构编写asynchronous代码。 但这并不意味着所有的function都应该被标记为asyncasync将函数包装为promise,如果函数执行同步代码,则此包装可能会导致错误(您希望string为例,但函数返回已解决的promise)。 另一个例子,当函数执行asynchronous代码,但不使用中间结果,在这种情况下,只要返回asynchronous调用的结果就足够了。

您应该在以下情况下使用async/await

  • 该函数执行同步代码,并且要将结果包装为承诺(用于创build承诺链)。
  • 该函数执行asynchronous代码,您需要一个中间结果。
  • 该函数执行asynchronous代码,并且不需要中间结果,但是需要串行执行代码(例如,处理数组中的每个项目)。

我们来看一些例子:

1.sync函数,validationuserIdvalidateParams返回true/false ,如果userId未定义,则validateParams2将引发错误。 validateParams3返回一个promise,可以用来创build一个promise链: validateParams3().then(...)

 let validateParams = (userId) => { return userId; } let validateParams2 = (userId) => { if (!userId) { throw new Error('userId is undefined'); } } let validateParams3 = (userId) => { if (!userId) { return Promise.reject(new Error('userId is undefined')); } return Promise.resolve(); } 

2.asyncfunction,不使用中间结果。 getUser返回一个挂起的promise(当userId有效时)或履行承诺(当userId是未定义的)。 它应该返回一个承诺,因为getUser可以用来启动承诺链: createUser().then(...)getUser2getUser3做同样的事情,返回一个承诺。 这个promise需要在这里避免出现unhandledError错误,因为validateParams2会抛出一个错误。 getUser2作为async (自动创build一个承诺), getUser3返回一个承诺。

 let getUser = (userId) => { if (validateParams(userId)) { return db.getUserById(userId); } return Promise.resolve(); } let getUser2 = async (userId) => { validateParams2(userId); return db.getUserById(userId); } let getUser3 = (userId) => { return Promise .resolve(userId) .then(validateParams2) .then(() => db.getUserById(userId); } 

3.asyncfunction,使用中间结果:

 let updateUser = async (userId, userData) => { let user = await getUser(userId); _.extend(user, userData); return db.saveUser(user); } 

上面的函数可以这样使用:

 // with async let fn = async (userId, userData) => { try { let user = await updateUser(userId, userData); console.log(user); } catch (err) { console.log(err); } } // without async let fn2 = (userId, userData) => { updateUser(userId, userData) .then(user => console.log(user)) .catch(err => console.log(err)) } }