如何等待函数或数据库查询? 然后处理结果并最终将其发回
我有这种情况:
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都应该被标记为async
。 async
将函数包装为promise,如果函数执行同步代码,则此包装可能会导致错误(您希望string为例,但函数返回已解决的promise)。 另一个例子,当函数执行asynchronous代码,但不使用中间结果,在这种情况下,只要返回asynchronous调用的结果就足够了。
您应该在以下情况下使用async/await
:
- 该函数执行同步代码,并且要将结果包装为承诺(用于创build承诺链)。
- 该函数执行asynchronous代码,您需要一个中间结果。
- 该函数执行asynchronous代码,并且不需要中间结果,但是需要串行执行代码(例如,处理数组中的每个项目)。
我们来看一些例子:
1.sync函数,validationuserId
。 validateParams
返回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(...)
。 getUser2
和getUser3
做同样的事情,返回一个承诺。 这个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)) } }