代码之家  ›  专栏  ›  技术社区  ›  KundaliniSin

异步函数的隐式Promise没有像我预期的那样解析

  •  1
  • KundaliniSin  · 技术社区  · 2 年前

    我知道所有标有的函数 async 返回Promise对象,即使它没有显式返回。所以我做了以下实验:

    async function getPromise() {
        setTimeout(() => { return "value"; }, 2000);
    }
    
    async function implicitPromiseTest() {
        const val = await getPromise();
        console.log(val);             // prints "undefined"
    }
    
    implicitPromiseTest();    
    

    在示例1中,后面的值 return 应该隐含地包装在Promise中。然后,此Promise将从函数中返回。我希望它能在 implicitPromiseTest 函数和返回的值-打印到控制台。

    我想这不起作用,因为来自 getPromise 从未真正解决。据我所知,完成这项任务的正确方法似乎是:

    async function getPromise() {
        return new Promise((resolve, reject) => 
          { setTimeout(() => { resolve("value"); }, 2000);})
    }
    
    async function implicitPromiseTest() {
        const val = await getPromise();
        console.log(val);             // prints "value"
    }
    

    但这给我提出了一些问题:

    1. 如何解析从异步函数隐式返回的Promise,而不从该函数的块显式返回Promise?这样的特性将使我能够大大简化代码。

    2. 如果不能做到这一点,那么异步总是隐式返回Promises又有什么意义呢?如果这些承诺无法解决或被拒绝,那么它们有什么用?

    3. 在我的第二个函数中 await 关键字应停止函数执行,直到Promise从 getPromise() 已解决。由于它永远不会解决,执行应该无限期地停止。那么为什么 console.log 处决

    2 回复  |  直到 2 年前
        1
  •  3
  •   Nicholas Tower    2 年前

    在示例1中,“return”之后的值应该隐式地包装在Promise中。

    它只会把承诺包裹在你归还的东西上 来自async函数 。中返回的值 setTimeout 回调函数将被忽略。

    所以现在发生的是:你的 async 函数开始运行,然后设置超时,然后隐式返回 undefined 。由于这是 异步 函数,即 未定义 被承诺包裹着。由于函数已完成执行,因此该promise处于已解析状态。过了一段时间,超时就结束了,但这对已经完成承诺解析的异步函数没有影响。

    async/await的存在是为了简化处理现有承诺的代码。它不接受非promise代码并将其转换为promise代码,除非返回非promise。如果你想从 setTimeout 或任何其他基于回调的函数,则必须使用 new Promise 构造函数。

    async总是隐式返回Promises有什么意义?

    因此,您不必以结束所有异步函数 return Promise.resolve(someValue) 。你可以改为 return someValue

    如:

    async function fetchStuff() {
      const response = await fetch('someurl');
      const data = await response.json();
      return data.userList; // instead of return Promise.resolve(data.userList)
    }
    

    在我的第二个函数中,“await”关键字应该停止函数执行,直到“getPromise()”中的Promise得到解析。既然它从未解决[…]

    这是一个错误的前提。在第一个例子中,promise立即解析,在第二个例子中它在超时时解析。现在它已经解析,任何等待它的代码都可以继续

        2
  •  0
  •   zcoop98    2 年前

    重要的是要记住 async / await 只是一个 不同的异步代码编写方式 ,并正常执行 Promises 在引擎盖下面。这些关键字可以将Promise链或嵌套的Promise变成更整洁、更易于阅读的顺序语句,这些语句看起来更像同步代码的其余部分。

    让我们分解一下第一个例子的各个部分,因为这里有些事情似乎引起了一些混乱。

    的默认返回值 async function

    正如您所注意到的,异步函数总是返回promise。

    即使函数没有 return 在这种情况下,是一个承诺 其解析为值 undefined 将被退回;在这种情况下,调用者将不会有任何需要“等待”的内容,因为返回的Promise已经被解决,并且可以解析为 未定义 立即返回。

    function syncFunc() {
      console.log('I return nothing');
    }
    
    async function asyncFunc() {
      console.log('I return nothing, but wrapped in a Promise');
    }
    
    console.log('syncFunc:', syncFunc());
    asyncFunc().then(val => console.log('asyncFunc:', val));

    setTimeout

    你的例子似乎是治疗 setTimeout 作为异步的, 但它不是Promise意义上的异步 调用的代码 setTimeout 不等它开火 然后继续。

    这意味着 getPromise() 电话 setTimeout 然后 立即返回 未定义 之后制作函数 异步 只是改变了它的方式 未定义 被包装在对其调用者的返回中,并且根本不会改变如何 setTimeout 治疗。

    如果我们从 setTimeout 的回调;它很快就着火了 getPromise 已经完成。

    async function getPromise() {
      setTimeout(() => console.log('setTimeout callback fired!'), 2000);
    }
    
    async function implicitPromiseTest() {
      console.log('Calling getPromise');
      await getPromise();
      console.log('getPromise finished');
    }
    
    implicitPromiseTest();    

    等候

    等候 展开/解析表达式;如果你 等候 一个承诺,你会得到该承诺的实现价值(一旦完成),如果你等待一个非承诺,你就会直接得到价值(例如。 await 3 只是给你 3 ).

    在您的代码中,通过调用 await getPromise() ,您正在解决由返回的Promise 异步函数 ; 从那以后 getPromise 没有显式返回,它返回 未定义 ,这就是承诺所实现的,以及 等候 拆封&返回。

    如果你打电话 getPromise() 没有 等候 ,您将获得最基本的承诺,然后可以手动链接 .then 在…上

    async function getPromise() {
        setTimeout(() => { return "value"; }, 2000);
    }
    
    async function implicitPromiseTest() {
            const promise = getPromise();
            promise.then(val => console.log("I'm resolved with the value:", val));
    }
    
    implicitPromiseTest();    

    如何解决从 异步 函数,而不从该函数的块显式返回Promise?

    你已经在用 等待getPromise() ! 只是因为上面解释的混乱,感觉不太对劲。

    如果不能做到这一点,那么还有什么意义 异步 总是含蓄地返回Promises?如果这些承诺无法解决或被拒绝,那么它们有什么用?

    他们可以而且确实如此;你只是 等候 立即点击它,这意味着你永远看不到承诺本身。

    您的代码正在有效地执行 await Promise.resolve(undefined) ,这只会产生 未定义 .

    在我的第二个函数中,“await”关键字应该停止函数执行,直到“getPromise()”中的Promise得到解析。由于它永远不会解决,执行应该无限期地停止。那么为什么要执行“console.log”呢?

    因为 承诺 决定 ,返回值为 getPromise ,即 未定义 .