javascript 为什么“throw Error”会使函数以同步方式运行?

ht4b089n  于 2023-05-16  发布在  Java
关注(0)|答案(2)|浏览(132)

我写了一些代码,发现了一些有趣的东西。
实施例1:

async function load(closure) {
    try {
      await closure();
    } catch (error) {
      console.log("error");
    } finally {
      console.log("finished");
    }
  }

  load(async () => {
    throw new Error();
  });

  console.log("hello");

该输出:

hello
error
finished

但是,如果我打电话:
实施例2:

load(() => {
  throw new Error();
});

输出为:

error
finished
hello

你能解释一下这是怎么回事吗?
我知道调用await会将执行排队到下一个时间点,因此第一个输出是预期的。
但是在第二个例子中,如果调用者使用的是await,为什么closure表现为一个同步函数?
这只会在抛出Error时发生。如果我打电话...
实施例3:

load(() => {
    return 1;
});

...那么closure在下一个tick中被调用。

nmpmafwu

nmpmafwu1#

查看文档
表达式的解析方式与Promise.resolve()相同:它总是被转换为本地Promise然后等待
在你的Example 2中,await没有被使用,因为错误发生在promise创建之前(即在执行closure函数期间)。该函数不返回任何值,因此不会转换为原生Promise。

  • 如果closure()不是async并抛出异常,则promise没有机会被创建,这就是为什么您首先看到errorfinished日志。实际上,由于closure函数尚未完全执行,因此未使用await
  • 如果closure()不是async并且返回一个值,它将被转换为promise,async函数将暂停直到下一个tick,这就是为什么你首先看到hello
  • 如果closure()不是async,并且返回了一个类似Promise.rejected()的rejected promise,你会首先看到hello,因为await收到了一个rejected promise,async函数会像之前一样暂停,直到下一个tick。
function fn() {
  throw new Error();
}

async function load() {
  try {
    await fn(); // like await Promise.resolve(fn())
  } catch (error) {
    console.error("
        I came here because an error occurred during fn execution.
        No promise has been created and await has not been used.
        The async function has not been paused.
    ");
  }
}
function fn() {
  return Promise.reject("error");
}
// same as
async function fn() {
  throw "error";
}

async function load() {
  try {
    await fn(); // like await Promise.reject()
  } catch (error) {
    console.error("
        I came here because await received a rejected promise.
        The async function has been paused until the next tick.
    ");
  }
}
zysjyyx4

zysjyyx42#

两个示例之间的差异是由于async/await语法在函数执行中引入了隐式延迟,导致finally块在console.log("hello")语句之后执行。

相关问题