使用await
关键字与不捕获{{1}}调用的返回值时省略关键字有何不同?
例如,创建这四个文件的方式是否存在差异?因为如果我运行此命令,则会创建所有这四个命令,所以我想知道。
await
我尝试了一些测试,看起来它的行为符合回答,但最后,情况变得很奇怪。
因此,如果您运行以下命令,
const fs = require('fs');
const { promisify } = require('util');
const writeFile = promisify(fs.writeFile);
(async function () {
await writeFile('a.txt', 'aaa');
await writeFile('b.txt', 'bbb');
writeFile('c.txt', 'ccc');
writeFile('d.txt', 'ddd');
})()
输出有时为writeFile('a.txt', 'foo');
writeFile('a.txt', 'bar');
const content = await readFile('a.txt', 'utf8');
console.log(content);
,有时为foo
,这似乎同时触发了两个bar
调用,最后完成的时间取决于运气。
所以我将其更改为:
writeFile
并且我认为(基于答案)这将始终输出writeFile('a.txt', 'foo');
await writeFile('a.txt', 'bar');
const content = await readFile('a.txt', 'utf8');
console.log(content);
,但是再次输出有时是bar
,有时是foo
。
我不确定我是否理解,因为我以为我已经等待写bar
的呼叫,因此唯一的解释是第一个bar
呼叫在等待的呼叫后以某种方式轮到了。
然后我不得不在通话之间设置延迟:
writeFile
这一次它总是输出writeFile('a.txt', 'foo');
[...Array(400000).fill('hello')].join('\n')
writeFile('a.txt', 'bar');
const content = await readFile('a.txt', 'utf8');
console.log(content);
。
然后发生了一些奇怪的事情。
如果运行以下命令:
bar
输出为writeFile('a.txt', 'foo');
[...Array(40000).fill('hello')].join('\n')
writeFile('a.txt', 'b');
const content = await readFile('a.txt', 'utf8');
console.log(content);
,我能想到的唯一解释是第一个boo
将writeFile
写入文件,然后第二个foo
开始写入文件,但在完成操作之前,等待的writeFile
会读取文件。 (笑)
答案 0 :(得分:2)
然后它不会await
结果。它将触发并忘记异步任务。在大多数情况下,这不是您想要的,因为代码乱序,并且错误未得到处理。
await writeFile(); // If an error occurs in writeFile, the promise returned by this function will reject too
await writeFile(); // this will definetly run after the previous call completed.
答案 1 :(得分:1)
在此示例代码中:
writeFile('a.txt', 'foo');
await writeFile('a.txt', 'bar');
const content = await readFile('a.txt', 'utf8');
console.log(content);
第一个writeFile
可能会随时等待完成,因为它没有被等待。您是否在等待写入bar
都没关系;这仅表示您的读取在第二次写入后完成。第一次写入可能会在此之后完成。这就是readFile
可以是foo
或bar
的原因。
也许可以通过显示未表示为异步函数的等效代码来可视化:
function doTheThing() {
writeFile('a.txt', 'foo');
return writeFile('a.txt', 'bar')
.then(() => {
// This happened after writing 'bar', but 'foo' may/may not have finished
return readFile('a.txt', 'utf8');
})
.then(content => {
console.log(content);
});
}
这是所谓的竞争条件。想想平行运行的轨迹:
File state
writeFile 'foo' writeFile 'bar'
|--- A --> |
| bar <----------|
|--- B --> v
|--- C --> readFile
| |
| ? ---------->|
| v
| console.log()
|--- D -->
因为我们不等待第一次写入,所以它可能在A,B,C,D点完成,或者可能永远不会完成(如果失败或需要很长时间)。
保证写顺序的唯一方法是使await
保持顺序:
await writeFile('a.txt', 'foo');
await writeFile('a.txt', 'bar');
const content = await readFile('a.txt', 'utf8');
console.log(content); // Always 'bar'
对于此代码块:
writeFile('a.txt', 'foo');
[...Array(40000).fill('hello')].join('\n')
writeFile('a.txt', 'b');
const content = await readFile('a.txt', 'utf8');
console.log(content);
...您是正确的,因为无论如何您都不在等待writeFile
,因此readFile
可能正在写入文件时正在读取文件。
答案 2 :(得分:0)
await
下的函数被执行,则在这种情况下需要 await
。
await
停止执行主线程,直到await
下的函数返回。