如何等待函数或数据库查询?然后处理结果,最后发送回去

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()

可能是什么问题?

ale*_*mac 6

您的代码中的主要问题是您正在混合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在以下时间使用

  • 该函数执行同步代码,并且您希望将结果包装到promise中(用于创建promise链).
  • 该函数执行异步代码,您需要一个中间结果.
  • 该函数执行异步代码,你并不需要一个中间结果,但要在一系列执行代码(在阵列例如处理每一个项目).

让我们考虑一些例子:

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(...).getUser2getUser3做同样的事情,回报承诺.这里要求承诺以避免unhandledError错误,因为validateParams2可能会抛出错误.getUser2makred 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)