异步函数 运行 顺序,为什么?

Async functions run sequential, why?

我对异步函数有点困惑。它说他们 return 一个承诺。承诺通常不会立即 运行 在其余代码之前,因为 javascript 使用 "run to completion" 方法。

但是如果异步函数 return 一个 promise,你怎么解释这个?


const _prefixJS = async file => {
  console.log('running...')
  fs.copyFileSync(file, `${file}.bak`);
  const content = fs.readFileSync(file, 'utf8');
  // Some modifications...
  fs.writeFileSync(file, newContent);
  console.log('stopping!')
};

console.log('start')
_prefixJS(f);
console.log('end')

// Output: start > running... > stopping! > end

在我看来,输出应该是:start > end > starting... > stopping!

因为承诺 运行 并发并且它们被放置在事件循环的末尾。

我知道那些方法仍然是同步的,但这不是主题。我目前正在从同步的 nodejs 方法转向异步方法。我只是问如果异步方法 return 一个承诺,它是如何在 end console.log 语句之前 运行s 的?

But if async functions return a promise, how can you explain this?

一个 async 函数运行 同步 直到第一个 awaitreturn(包括隐式 return)。 (当我说 "up to," 时,同步部分包括 awaitreturn 右边的操作数。)在那一点(awaitreturn),它return这是一个承诺。这样它就可以 启动 它应该启动的任何异步进程。这包含在规范 here.

你的 _prefixJS 不包含任何 awaitreturn,所以它同步运行到最后,returning 一个将被履行的承诺值 undefined.

要使您的 async 函数实际异步工作,您需要使用这些函数的 fs.promises 版本和 await 它们的结果。像这样(未经测试):

const fsp = require("fs").promises;
// ...
const _prefixJS = async file => {
  console.log('running...');
  await fsp.copyFile(file, `${file}.bak`);
  const content = await fsp.readFile(file, 'utf8');
  // Some modifications...
  await fsp.writeFile(file, newContent);
  console.log('stopping!');
};

有了那个函数,console.log('running'); 调用和 fsp.copyFile(...) 调用在调用 _prefixJS 时同步完成,然后函数 return 承诺并等待fsp.copyFile(...) 在异步继续其逻辑之前的结果。

fsp 函数使用占位符的实例:

const doWork = () => new Promise(resolve =>
    setTimeout(resolve, Math.random() * 2000));

const fsp = {
    async copyFile() {
        console.log("copyFile started");
        await doWork();
        console.log("copyFile returning");
    },
    async readFile() {
        console.log("readFile started");
        await doWork();
        console.log("readFile returning");
    },
    async writeFile() {
        console.log("writeFile started");
        await doWork();
        console.log("writeFile returning");
    }
};

const _prefixJS = async file => {
    console.log('running...');
    await fsp.copyFile(file, `${file}.bak`);
    const content = await fsp.readFile(file, 'utf8');
    // Some modifications...
    await fsp.writeFile(file, "newContent");
    console.log('stopping!');
};

console.log("calling _prefixJS");
_prefixJS()
.then(() => {
    console.log("then handler on _prefixJS()");
})
.catch(error => {
    console.log(`catch handler on _prefixJS(): ${error.message}`);
});
console.log("calling _prefixJS - done");