Async/await 再次:等待和 return 放在哪里?

Async/await again: Where to put await and return?

在 VSCode 扩展中,我有一个函数可以从当前工作区中删除某些目录。但是该函数不会等待目录被删除。

The accepted answer for this Whosebug question 有道理,但我仍然不知道如何使我的函数正常工作。我在哪里放置 await 和 return?

async function cleanUpWorkspace(workspace: any) {
    const fs = require('fs');
    const rimraf = require("rimraf");
    var targetFolders = ['dirA', 'dirB', 'dirC', 'dirD'];

    try {
        await targetFolders.forEach(function (value) { //'await' has no effect on the type of this expression.
            let targetPath = workspace + "\\" + value;
            if (fs.existsSync(targetPath)) {
                fs.promises.access(targetPath);
                rimraf(targetPath, function (err: any) {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log("Directory: " + value + " was deleted");
                    }
                });
            } else {
                console.log(value + " doesn't exist.");
            }
        });
        return Promise.resolve();
    } catch (error) {
        console.log(error);
    }
}

async function prepare() {
    await cleanUpWorkspace(workspace);
}
  • 您只能在 async function 或异步箭头函数 (async () => { /* function contents */ }) 中使用 await
  • 您应该只在 return 一个 Promise
  • 的函数上使用 await
  • 所有async函数,无论它们是否return一个值,return一个Promise。如果里面没有 return 值,则 return 类型是 Promise<void> (类似于常规函数隐式 return void 如果它们没有一个 return 值)

您正在尝试在传递给 forEach 的函数内部执行异步操作(即调用 return 承诺的函数)。理想情况下,我们会 await 他们。要使用 await,我们需要将传递给 forEach 的函数设为 async 函数。然而,forEach 并没有在内部 await 承诺。这意味着 forEach 函数中未捕获的异常不会弥补 try/catch 块。

为了避免这种情况,我们可以使用 for..of 循环。

因为 async 自动运行 return 和 Promise,所以没有理由需要 return Promise.resolve()

  try {
      for (const value of targetFolders) {
        let targetPath = workspace + "\\" + value;
        if (fs.existsSync(targetPath)) {
            await fs.promises.access(targetPath);
            rimraf(targetPath, function (err: any) {
                if (err) {
                    console.log(err);
                } else {
                    console.log("Directory: " + value + " was deleted");
                }
            });
        } else {
            console.log(value + " doesn't exist.");
        }
      }
  } catch (error) {
      console.log(error);
  }

现在,我们可以 await fs.promises.access 调用。


我们可以做的另一件事是 promisify rimraf。 Node 标准库中有一个函数 -- util.promisify -- 将接受回调的函数转换为函数 returning promises。所以,如果我们有

const util = require("util")
const rimrafPromise = util.promisify(rimraf)

那我们可以做

  try {
      for (const value of targetFolders) {
        let targetPath = workspace + "\\" + value;
        if (fs.existsSync(targetPath)) {
            await fs.promises.access(targetPath);
            await rimrafPromise(targetPath);
            console.log("Directory: " + value + " was deleted");
        } else {
            console.log(value + " doesn't exist.");
        }
      }
  } catch (error) {
      console.log(error);
  }