如何等待函数或数据库查询?然后处理结果,最后发回
Posted
技术标签:
【中文标题】如何等待函数或数据库查询?然后处理结果,最后发回【英文标题】:How to await for a function or a database query? And then process results and finally send them back 【发布时间】:2018-01-27 15:21:29 【问题描述】:我有这种情况:
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()
时没有准备好
可能是什么问题?
【问题讨论】:
【参考方案1】:您的代码中的主要问题是您混合了async/await
语法和回调。仅当您想对该函数内部的异步调用结果执行某些操作时,才使用async
函数。
此外,针对您的情况,您需要promisify connection.query()
- 创建一个承诺。请参阅下面带有工作代码的正确模式:
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
的强大之处在于它允许您使用同步语言结构编写异步代码。但这并不意味着所有函数都应标记为async
。 async
将函数包装成 promise,如果函数执行同步代码,这种包装会导致错误(例如,您期望字符串,但函数返回已解析的 promise)。另一个例子,函数执行异步代码,但不使用中间结果,在这种情况下,只返回异步调用的结果就足够了。
您应该在以下情况下使用async/await
:
让我们考虑一些例子:
1.sync 函数,验证userId
。 validateParams
返回 true/false
,如果 userId
未定义,validateParams2
将引发错误。 validateParams3
返回一个 Promise,可用于创建 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.async 函数,不使用中间结果。 getUser
返回待处理的承诺(当userId
有效时)或已履行的承诺(当userId
未定义时)。它应该返回一个承诺,因为getUser
可用于启动承诺链:createUser().then(...)
。 getUser2
和 getUser3
做同样的事情,返回一个承诺。此处需要 promise 以避免出现 unhandledError
错误,因为 validateParams2
可能会抛出错误。 getUser2
makred 为 async
(自动创建一个 Promise),getUser3
返回一个 Promise。
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.async 函数,使用中间结果:
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))
【讨论】:
谢谢 Alex,您能否解释或提供有关“仅当您想在此函数内对异步调用的结果执行某些操作时才使用异步函数的更多信息/示例。 " 因为我将更改标题以获取更一般的主题以帮助其他用户。我真的很感激,因为这对我来说也是一个学习过程。 @KhalilKhalaf 添加了有关使用async/await
的说明。
我不明白你为什么改变了我的例子,并说它不起作用?为什么在connection.query
中添加回调?您还在bar
中添加了records.map
...所以目前这是完全不同的问题。我的回答是针对原始问题。
我明白了,我知道问题出在哪里connection.query
没有返回承诺(我以为它会返回......)。你需要promisify connection.query
- 创建一个promise。更新了代码。
:),很高兴能帮到你,connection.query
让我有点困惑。以上是关于如何等待函数或数据库查询?然后处理结果,最后发回的主要内容,如果未能解决你的问题,请参考以下文章
java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring Even