Kha*_*laf 4 javascript node.js promise async-await
我有这种情况:
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);
}
Run Code Online (Sandbox Code Playgroud)
简述:
我收到客户的GET请求
我调用foo()查询数据库并在结果上应用函数
我使用第三方API处理结果,需要时间才能完成
我将最终结果发回给客户
我期待看到:
查询就绪 - >内部栏 - >完成栏 - >响应就绪
但我改为看到:
响应就绪 - >查询就绪 - >内部栏 - >栏完成
客户端正在接收,undefined
因为什么时候都没有准response.send()
可能是什么问题?
您的代码中的主要问题是您正在混合async/await
语法和回调.async
仅当您想要在此函数内执行异步调用的结果时才使用函数.
另外,根据您的情况,您需要实现承诺 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);
}
Run Code Online (Sandbox Code Playgroud)
关于使用的说明async/await
.它的强大之async/await
处在于它允许您使用同步语言结构编写异步代码.但这并不意味着所有功能都应标记为async
.async
将函数包装到promise中,如果函数执行同步代码,此包装可能会导致错误(例如,您希望字符串,但函数返回已解析的promise).另一个例子是当函数执行异步代码但不使用中间结果时,在这种情况下只需返回异步调用的结果即可.
您应该async/await
在以下时间使用
让我们考虑一些例子:
1.sync功能,验证userId
.validateParams
返回true/false
,validateParams2
如果userId
未定义则抛出错误.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();
}
Run Code Online (Sandbox Code Playgroud)
2.async功能,不使用中间结果.getUser
返回挂起的promise(何时userId
有效)或履行的promise(userId
未定义时).它应该返回一个promise,因为getUser
它可以用于启动一个promise链:createUser().then(...)
.getUser2
并getUser3
做同样的事情,回报承诺.这里要求承诺以避免unhandledError
错误,因为validateParams2
可能会抛出错误.getUser2
makred as 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);
}
Run Code Online (Sandbox Code Playgroud)
3.async函数,使用中间结果:
let updateUser = async (userId, userData) => {
let user = await getUser(userId);
_.extend(user, userData);
return db.saveUser(user);
}
Run Code Online (Sandbox Code Playgroud)
上面的函数可以这样使用:
// 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))
}
}
Run Code Online (Sandbox Code Playgroud)