我是异步函数的新手,并且我对应该如何等待有一些疑问。我具有以下功能,但对输出感到困惑。
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和异步函数如何工作的信息,但由于无法解决这个问题,因此,不胜感激。
答案 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