等待解决,然后继续

时间:2020-07-07 18:23:14

标签: node.js asynchronous async-await

我是异步函数的新手,并且我对应该如何等待有一些疑问。我具有以下功能,但对输出感到困惑。

arrayA = []
arrayB = []
con.query('SELECT * FROM table', async function(err, result) {
  test = await 'test';
  console.log(test);
  if (err) throw err;
  n = 0;
  for (var column of Object.keys(result)) {
    arrayA[n] = await result[column].A;
    arrayB[n] = await result[column].B;
    n = n+1;
  }
});
console.log(arrayA);

我期望的输出是:

test
[
    "item 1"
    "item 2"
    ...
    "item n"
]

但是我得到的是:

[]
test

鉴于此,很明显,它在继续甚至写入测试变量之前不等待阵列被填充。我一直到处都在阅读有关Promise和异步函数如何工作的信息,但由于无法解决这个问题,因此,不胜感激。

3 个答案:

答案 0 :(得分:3)

您在这里混合了两个概念。您的SQL执行使用的是回调函数,查询完成执行后便会调用该函数。这并不是阻塞(这就是为什么您会立即看到空数组的原因。)

您现在已将回调函数定义为async,这意味着您可以在其中await执行其他异步操作。然后,此await被阻止,但仅在此执行上下文(函数)的上下文中。鉴于字符串分配实际上并不是异步操作,因此它的行为可能与正常执行该函数没有什么不同。

答案 1 :(得分:3)

con.query是异步的,因此是回调函数,因此最后一个console.log(arrayA)不会等待con.query(以及其中的回调函数)在执行之前完成。

事件的顺序(用注释表示)如下:

# 1
arrayA = []
# 2
arrayB = []
# 3 (the query is sent to the server, but we do not wait for a response
con.query('SELECT * FROM table', async function(err, result) {
  # 5 (await will "pause execution" for the 
  #   expression to the right, a string is not a promise so this doesn't do anything
  test = await 'test';
  # 6
  console.log(test);
  # 7
  if (err) throw err;
  # 8
  n = 0;
  # 9, 10, etc
  for (var column of Object.keys(result)) {
    # is result[column].A a promise? if not, await won't do anything.
    arrayA[n] = await result[column].A;
    arrayB[n] = await result[column].B;
    n = n+1;
  }
});
# 4 (still waiting on the server to respond, callback is "scheduled")
console.log(arrayA);

您需要做的是await con.query,但是由于它使用了等待回调,因此您将无法使用Promise或“ promisify”:

(async () => {

  arrayA = []
  arrayB = []  

  // wait until resolve is called
  await new Promise((resolve, reject) => {
    con.query("SELECT * FROM table", async function (err, result) {
      if (err) return reject(err);
      for (var column of Object.keys(result)) {
        arrayA[n] = result[column].A;
        arrayB[n] = result[column].B;
      }
      // you can await more things here if you need to
      // calling resolve here resolves the promise we are awaiting for con.query
      resolve();
    });
  });

  // since we awaited a promise above, con.query should be done
  console.log(arrayA);

})().catch((e) => { 
  console.error(e); 
  process.exit(1) 
});

同时使用回调和Promise总是有点冗长。许多库都实现了Promise接口,因此,如果您使用的mysql客户端库支持Promise接口,则您可以像下面这样简单:

const rows = await con.query("SELECT * FROM table");

rows.forEach(row => { ... });

答案 2 :(得分:0)

有多种方法可以解决问题。但这是最方便的。

var arrayA = [];
var arrayB = [];
try {
  var result = await con.query("SELECT * FROM table");
  n = 0;
  for (var column of Object.keys(result)) {
    arrayA[n] = await result[column].A;
    arrayB[n] = await result[column].B;
    n = n + 1;
  }
  console.log(arrayA);
} catch (err) {
  console.log(err);
}

您可以阅读有关此主题的更多信息here