【问题标题】:Shouldn't async return a Promise without explicitly wrapping the return value in a Promise?不应该在没有明确地将返回值包装在 Promise 中的情况下异步返回 Promise 吗?
【发布时间】:2018-07-15 18:55:42
【问题描述】:

MDN documentation 声明

当调用异步函数时,它会返回一个 Promise。当异步 函数返回一个值,Promise 将被解析为 返回值。当异步函数抛出异常或某些 值,Promise 将被抛出的值拒绝。

因此,考虑到 await 期望得到已解决的承诺,我做错了什么?

foo();

async function foo(){
    await bar();
    zoo();
}

async function bar(){
    setTimeout(() => {
        console.log("bar");
        return;
    }, 1000);    
}

function zoo(){
    console.log("zoo");    
}

根据我(错误地)理解,它应该首先记录bar,然后是zoo,但它正在以相反的方式记录。

编辑:现在,感谢@Matt Morgan 的澄清,我理解了这个错误,因为bar() 函数返回undefined。尽管如此,我认为单独调用 async 函数 per se 会使该函数立即返回一个未解决的承诺,并且当 async 函数返回任何值时,这样的承诺将被解决(甚至不明确的)。但我现在意识到一个人真的需要通过return Promise 声明来回报自己的承诺。我认为 async 的 MDN 文章(我已全部阅读)在这个主题上有点混乱(只是我的看法)。

因此,我可以简单地将我的 bar() 函数修改为:

function bar(){
    return new Promise(function(resolve){
        setTimeout(() => {
            console.log("bar");
            resolve();
        }, 1000);
    });
}

【问题讨论】:

  • 在您刚刚发布的链接中,查看resolveAfter2Seconds 的代码,然后将其与您的 bar() 进行比较。注意到什么了吗?
  • @Will,我阅读了所有文章和示例,但我不明白如果异步函数已经通过简单地运行 @987654337 返回了 Promise,为什么还需要返回 Promise @。文档说“当调用异步函数时,它返回一个 Promise。当异步函数返回一个值时,Promise 将使用返回的值解析”
  • @Will 因此“我知道如何让它工作”,我只是不明白为什么它会那样工作:)
  • 有趣。返回值会自动包装在 Promise 中。这肯定会减少样板。整洁。
  • 1) return 不跨越函数边界。您只在回调内部返回。该函数将返回给它的调用者。但是你不是回调的调用者,浏览器会在超时时调用该函数。对setTimeout 的调用会立即返回。它没有阻塞。 2) 如果你显式地创建并返回一个 Promise,那么你就不需要 async。如果您希望能够在函数中使用 await,则需要 async。

标签: javascript async-await ecmascript-2017


【解决方案1】:

bar()正在设置超时并返回未定义,这与在超时结束时立即运行日志记录语句不同。

所以,zoo() 运行,然后当超时结束时(1000 毫秒后),您会在控制台中看到“bar”。

这是一个修改后的示例没有超时:

foo();

async function foo(){
    await bar();
    zoo();
}

async function bar(){
   console.log("bar");   
}

function zoo(){
    console.log("zoo");    
}

没有setTimeout,你会得到你期望的执行顺序。

第二个示例,您有一个 delay() 函数,该函数将 setTimeout 包装在一个 Promise 中:

foo();

async function foo(){
    await bar();
    zoo();
}

async function bar(){
   await delay();
   console.log("bar");   
}

function delay(t, v) {
   return new Promise(function(resolve) { 
       setTimeout(resolve.bind(null, v), t)
   });
}

function zoo(){
    console.log("zoo");    
}

最后的sn-p 是否等待promise的解析,所以你看到bar,然后是foo

以上delay取自https://stackoverflow.com/a/39538518/3084820

这是最后一个示例,bar() 返回“bar”。这意味着它被 async 声明包裹在一个 Promise 中,并由 await 内部的 foo() 解决同样,你会看到你期望看到的。

foo();

async function foo(){
    console.log(await bar());
    zoo();
}

async function bar(){
    return 'bar';   
}

function zoo(){
    console.log("zoo");    
}

了解您的原始示例不返回值bar 很重要。它返回undefined,如果您更改原始代码以注销bar() 的返回值,您会在控制台中看到三件事:

  1. 立即返回的承诺表单 bar() 解析为 undefined
  2. 来自zoo() 函数的值zoo
  3. 最后,经过 1000 毫秒后,您会看到 bar 从被推送到队列中的 setTimeout 记录下来。

试一试,看看你会得到什么。

【讨论】:

  • 感谢您的回复,我完全理解您的代码。在您的第一个示例中,不需要async,它只是一个命令序列;在我已经使用的第二个示例中,您返回一个Promise,但我不明白为什么如果异步函数已经通过简单地运行return 返回一个Promise,您需要返回一个Promise跨度>
  • 函数bar返回undefined。在您的原始代码中,您设置了一个超时,这实际上与承诺没有任何关系。为了测试异步行为,您需要有一个在超时完成时解决的承诺,这就是我包含第二个示例的原因。
  • 好的,但是 MDN 文档说“当调用异步函数时,它会返回一个 Promise。当异步函数返回一个值时,Promise 将使用返回值解析”。搞得一头雾水!
  • 并且该承诺立即以undefined 的值解决。我认为您会感到困惑,认为 promise 的解决将导致 console.log 语句被执行。
  • setTimeout 利用浏览器 API 在一定时间后将包装的函数插入队列。它不会产生承诺。你的函数设置了超时,然后返回undefined,promise 解析为undefined
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 2020-07-09
相关资源
最近更新 更多