JS:异步函数隐式解开 Promise?

zzr*_*zrv 2 javascript asynchronous node.js promise async-await

据我所知,异步函数将其返回值隐式包装到承诺中。这确实适用于所有属性,除了 Promise 本身。

async function f() {
  return new Promise((res) => {
    setTimeout(() => {
      res("Why am I being unwrapped")
    }, 1000)
  })
}

(async () => {
  console.log(await f())
})()
Run Code Online (Sandbox Code Playgroud)

那些在退回之前会被拆开。所以这await f()实际上等待着两个嵌套的承诺。

请注意,这也适用于显式创建的 Promises ( Promise.resolve(new Promise(...)))

有没有好的办法避免这种情况呢?我真的很想有一个嵌套的 Promise,而不需要像这样的快速修复。

async function y() {
  return {wrapped: new Promise((res) => {
    setTimeout(() => {
      res("Why am I being unwrapped")
    }, 1000)
  })}
}

(async () => {
  console.log((await y()).wrapped)
})()
Run Code Online (Sandbox Code Playgroud)

沙盒

tad*_*man 7

根据MDN 函数async文档

异步函数总是返回一个承诺。如果异步函数的返回值不是显式的 Promise,它将隐式包装在 Promise 中。

换句话说,由于您返回的是 Promise,所以它不会被包装。如果你想重新包装它,你可以,但你也可以删除async具有类似效果的关键字。除非你这样做,否则你会得到原始的 Promise await

如此有效:

function f() {
  return new Promise((res) => {
    setTimeout(() => {
      res("Might be wrappers on some of you, but not on me!")
    }, 1000)
  })
}

(async () => {
  console.log(f())
})()
Run Code Online (Sandbox Code Playgroud)

这会给你这样的输出:

Promise { <pending> }
Run Code Online (Sandbox Code Playgroud)

如果目标是有一个返回原始 Promise 的 Promise,那么您将与 Promise 系统设计要做的所有事情作斗争,即在发现 Promise 时自动解开它们。Promise.resolve()包装除Promise之外的所有内容,如果您以某种方式给它一个 Promise,它就会递归地展开它。

您可以通过返回一些不是 Promise 的东西来做到这一点,就像在您的示例中一样,但这似乎确实违背了 Promise 的整个目的。

如果您正在尝试解决一个绝对需要延迟 Promise 的特定问题,请考虑返回一个函数而不是某个任意对象:

function f() {
  return () => {
    return new Promise((res) => {
      setTimeout(() => {
        res("I'll start as soon as you ask.")
      }, 1000)
    })
  };
}
Run Code Online (Sandbox Code Playgroud)

然后你可以打电话let p = f(),稍后p()当你想得到一个实际的 Promise 时。这就是 JavaScript 通常处理延迟执行的方式。

如果你想立即启动 Promise 的执行,你仍然可以满足:

function f() {
  const p = new Promise((res) => {
    setTimeout(() => {
      res("Already underway when requested.")
    }, 1000)
  })

  return () => { p };
}
Run Code Online (Sandbox Code Playgroud)

不过,如果可能的话,通常最好避免使用这些技术,而且通常也是如此。