【问题标题】:Why is my async function returning a pending promise after await?为什么我的异步函数在等待后返回待处理的承诺?
【发布时间】:2021-01-02 23:14:05
【问题描述】:

我一定是在这里遗漏了一些东西,因为我不明白为什么我的 promise 没有解决。

我把代码归结为这个简单的例子:

  ...
  console.log("before");
  const promise = second();
  console.log("after");
  console.log(promise);
  ...

async function first() {
  const p1 = await axios.get("https://<url>");
  console.log("first");
  console.log(p1.data);
  return (p1);
}

async function second() {
  const p2 = await first();
  console.log("second");
  console.log(p2.data);
  return (p2);
};

在控制台中产生这个输出:

before
after
Promise { <pending> }
first
p1.data
second
p2.data

我的理解是 await 会暂停执行,直到它完成,然后再转到下一行,但这显然不会发生。

初始块以 pending promise 结束,然后 async 函数中的 awaited 代码执行而不是暂停。

我缺少什么让我的代码暂停并等到 await 行以 resolved promise 完成后再继续?

【问题讨论】:

  • await for second()
  • async 函数总是返回一个最初为 Pending 的 Promise ... async 函数就是这样做的
  • 您在没有等待的情况下调用异步函数,这就是它显示 Promise 未决的原因。您需要将 await 放在 second() 之前。

标签: javascript node.js promise async-await


【解决方案1】:

异步函数就像一个不会立即解析的 Promise。所以你可能应该使用一个立即调用的匿名异步函数:

(async()=>{
  console.log("before");
  const promise = await second();
  console.log("after");
  console.log(promise);
})();

【讨论】:

  • "异步函数是 Promise..." - 这是一个返回 Promise 的函数。 “所以你可能应该使用立即调用的匿名异步函数” - 这将如何改变任何事情?真正的变化是 await second() - 它只适用于 async 函数。
  • 这只是命名法。我们不能在异步函数之外使用“等待”。如果我们需要在全局范围内的任何函数之外调用 console.log() 怎么办?
  • 是吗? const x = async function() { }; y = new Promise(() =&gt; {}); console.log(typeof x, typeof y) - “我们不能在异步函数之外使用 'await'” - 这就是您添加 IIFE 的原因,但这不是现在答案符合 OP 要求的原因。这是await
  • 说“这是一个返回承诺的函数。”对我来说似乎很困惑,因为函数内部“返回”之后的内容不一定是 Promise。 'typeof' 没有说太多。这只是观点和措辞的问题。
  • async function: “异步函数总是返回一个promise。如果异步函数的返回值不是明确的promise,它将被隐式地包装在promise中。”
【解决方案2】:

async function 实际上并不是我们想象的同步函数,它是一个承诺。所以你需要像 Promise 一样处理它:

console.log("before");
second().then(res => {
  console.log("after");
  console.log(res);
});

【讨论】:

  • awaiting it is 像承诺一样处理它。我认为这个答案与问题无关,即关于控制台中的Promise { &lt;pending&gt; } 输出。
  • 这实际上确实解决了承诺,我可以使用它来获得我需要的东西,但我总是看到 .then() 在直接处理承诺时使用。我从未见过与 async/await 一起使用的 .then() 子句(这可能就是我遇到这么多麻烦的原因),并且好奇是否有替代语法可以在没有 .then() 的情况下完成相同的事情。
  • @GRW 替代语法 async/await。 ? 如果你有一个 async 函数,你可以在另一个异步函数中 await 它,或者你可以将 .thens 链接到它。相反,如果你有一个thenable,你可以在一个异步函数中await它来获得它的结果。
  • @GRW 较新的方法是在second() 前面添加await,例如await second()。但是您将需要再次使用 async 函数来调用您的 second()
【解决方案3】:

在 JavaScript 中,以下所有条件都成立:

承诺

  • 是一个值(可以传递给函数、分配给变量等等)
  • 可以处于已解决已拒绝待处理状态
  • 它解析的东西也是一个值(1"foo"{},...)
  • 可以将 .then(...) 回调链接到它
  • 可以awaited

async 函数

  • 是一个同步返回promise的函数
  • 是一个异步返回该承诺的解析值的函数

希望这个修改后的例子能让它更清楚:

// mock axios
const axios = {
    get: url => Promise.resolve({ data: `Some data from ${url}` })
}

const fetchMockData = async () => {
    const val = await axios.get('https://<url>')
    return val
}

const withAsyncAwait = async () => {
    console.log('=== with async/await ===')
    
    const promise = fetchMockData() // not awaited
    console.log('type of promise:', promise.constructor.name)
    const resolved = await promise // here we await it
    console.log('type of resolved:', resolved.constructor.name)
    console.log('data:', resolved.data)
}

// equivalent but with `then` callback
const withThenCallback = () => {
    console.log('=== with then callback ===')
    
    const promise = fetchMockData() // not awaited
    console.log('type of promise:', promise.constructor.name)
    promise.then(resolved => { // resolved thanks to `then`
        console.log('type of resolved:', resolved.constructor.name)
        console.log('data:', resolved.data)
    })
}

setTimeout(withAsyncAwait, 0)
setTimeout(withThenCallback, 100)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2019-07-20
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    相关资源
    最近更新 更多