【问题标题】:How to access the value of a promise?如何访问承诺的价值?
【发布时间】:2021-07-11 05:05:42
【问题描述】:

我正在查看 Angular 文档中的 $q 示例,但我认为这可能适用于一般的承诺。下面的示例是从他们的文档中逐字复制的,其中包括他们的评论:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

我不清楚这是如何工作的。如果我可以在第一个.then() 的结果上调用.then(),将它们链接起来,我知道我可以,那么promiseB 是一个承诺对象,类型为Object。它不是Number。那么“它的值将是 promiseA 加 1 的结果”是什么意思呢?

我应该以promiseB.value 或类似的方式访问它吗?成功回调如何返回一个承诺并返回“result + 1”?我错过了一些东西。

【问题讨论】:

标签: javascript angularjs promise angular-promise


【解决方案1】:

promiseAthen函数返回一个新的promise(promiseB),在promiseA被解析后立即被解析,它的值是promiseA中成功函数返回的值.

在这种情况下,promiseA 被解析为 result,然后立即将 promiseB 解析为 result + 1

访问promiseB 的值与访问promiseA 的结果的方式相同。

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

2019 年 12 月编辑async/await 现在是 JS 中的标准,它允许使用上述方法的替代语法。你现在可以写:

let result = await functionThatReturnsPromiseA();
result = result + 1;

现在没有promiseB,因为我们已经使用await解开promiseA的结果,你可以直接使用它。

但是,await 只能在 async 函数内使用。所以要稍微缩小一点,上面的内容必须像这样包含:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}

【讨论】:

  • Promise 理论上是它们自己的对象。它们包含一个可以通过 promise 的成功函数访问的结果。
  • 因此,如果您想使用 Promise 的异步回调的返回值,则必须在另一个异步回调中完成。说得通。我一直在寻找一种方法来获得一些最终的原始返回值,但我认为根据上下文,这将无法解释。
  • @Aerovistae 实际上,ES6 引入了使这成为可能的生成器,而 ES7 引入了异步函数——两者都为你提供了语法糖,而不是承诺,使其看起来像同步代码(通过在后台运行状态机) - 所以紧紧抓住:)
  • 答案第一行的立即解决是什么意思?
【解决方案2】:

当一个 promise 被解决/拒绝时,它将调用它的成功/错误处理程序:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

then 方法还返回一个 promise:promiseB,它将被解析/拒绝取决于来自 promiseA 的成功/错误处理程序的返回值

promiseA 的成功/错误处理程序可以返回三个可能的值,这些值会影响 promiseB 的结果:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise
   

有了这种理解,您就可以理解以下内容:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

then 调用立即返回 promiseB。 当 promiseA 被解析时,它会将结果传递给 promiseA 的成功处理程序。 由于返回值是 promiseA 的结果 + 1,所以成功处理程序正在返回一个值(上面的选项 2),所以 promiseB 将立即解析,并且 promiseB 的成功处理程序将传递 promiseA 的结果 + 1。

【讨论】:

    【解决方案3】:

    promiseB 的.then 函数接收promiseA 的.then 函数返回的内容。

    这里promiseA返回的是一个数字,它将在promiseB的成功函数中作为number参数使用。然后将增加 1

    【讨论】:

      【解决方案4】:

      pixelbits 的答案是正确的,您应该始终使用.then() 来访问生产代码中的承诺值。

      但是,有一种方法可以在使用以下不受支持的内部 node.js 绑定解决 promise 后直接访问它的值:

      process.binding('util').getPromiseDetails(myPromise)[1]
      

      警告:process.binding 从未打算在 nodejs 核心之外使用,nodejs 核心团队正在积极寻求弃用它

      https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/issues/22064

      【讨论】:

        【解决方案5】:

        解析评论与您当前的理解稍有不同可能会有所帮助:

        // promiseB will be resolved immediately after promiseA is resolved
        

        这表明promiseB 是一个承诺,但会在promiseA 解决后立即解决。另一种看待这意味着promiseA.then() 返回分配给promiseB 的承诺。

        // and its value will be the result of promiseA incremented by 1
        

        这意味着promiseA 解析为的值是promiseB 将接收的作为其successCallback 值的值:

        promiseB.then(function (val) {
          // val is now promiseA's result + 1
        });
        

        【讨论】:

          【解决方案6】:

          上面有一些很好的答案,这里是 ES6 箭头函数版本

          var something = async() => {
             let result = await functionThatReturnsPromiseA();
             return result + 1;
          }
          

          【讨论】:

            【解决方案7】:

            在 Node REPL 中,为了获得一个承诺值的数据库连接,我采用了以下方法:

            let connection
            try {
              (async () => {
                connection = await returnsAPromiseResolvingToConnection()
              })()
            } catch(err) {
              console.log(err)
            }
            

            带有await 的行通常会返回一个承诺。此代码可以粘贴到 Node REPL 中,或者如果保存在 index.js 中,则可以使用

            在 Bash 中运行
            node -i -e "$(< index.js)"
            

            在运行脚本并访问 set 变量后,您将留在 Node REPL 中。要确认异步函数已经返回,您可以记录connection,然后您就可以使用该变量了。对于异步函数之外的脚本中的任何代码,我们当然不想指望异步函数正在解析。

            【讨论】:

            • 这里是颤音。非常合法。也适用于 ts-node。
            【解决方案8】:

            我是 javascript promise 的缓慢学习者,默认情况下所有异步函数都返回一个 promise,您可以将结果包装为:

            (async () => {
            //Optional "await"
              await yourAsyncFunctionOrPromise()
                .then(function (result) {
                  return result +1;
                })
                .catch(function (error) {
                  return error;
                })()
            })
            

            "await 表达式导致 async 函数执行暂停,直到一个 Promise 被解决(即完成或拒绝),并在完成后恢复异步函数的执行。当恢复时,await 表达式的值是应验的应许。 如果 Promise 被拒绝,则 await 表达式会抛出被拒绝的值。"

            MDN Web Docs 上阅读有关 awaitpromises 的更多信息

            【讨论】:

              【解决方案9】:

              实际上,从交互式 (node.js) 提示符中,可以“等待”:

              > y = new Promise((resolve, reject) => resolve(23));
              Promise {
                 23,
                 [Symbol(async_id_symbol)]: 10419,
                 [Symbol(trigger_async_id_symbol)]: 5,
                 [Symbol(destroyed)]: { destroyed: false }
              }
              > v = await y;
              23
              

              这在 repl 进行实验时很有用。

              你不能在“普通”函数中这样做:

              > function foo() { let z = await y; return z; }
              Uncaught SyntaxError: 
              Unexpected token 'y'
              

              您可以在“异步函数”中执行此操作,但这会让您保留一个承诺,而不是您想要的值:

              > async function foo() { let z = await y; return z; }
              undefined
              > foo()
              Promise {
                <pending>,
                [Symbol(async_id_symbol)]: 10571,
                [Symbol(trigger_async_id_symbol)]: 5,
                [Symbol(destroyed)]: { destroyed: false }
              }
              

              【讨论】:

                【解决方案10】:
                promiseA(pram).then(
                     result => { 
                     //make sure promiseA function allready success and response
                     //do something here
                }).catch(err => console.log(err)) => {
                     // handle error with try catch
                }
                

                【讨论】:

                • 虽然此代码可以回答问题,但提供有关 如何为什么 解决问题的附加上下文将提高​​答案的长期价值。
                【解决方案11】:

                在交互式提示下进行实验时,可以通过将值分配给“then()”函数中的全局变量来访问 Promise 的值,例如:

                > promise = new Promise((resolve, reject) => resolve(17));
                Promise {
                   17,
                   [Symbol(async_id_symbol)]: 7600,
                   [Symbol(trigger_async_id_symbol)]: 5,
                   [Symbol(destroyed)]: { destroyed: false }
                }
                > global_cheat = null;
                null
                > promise.then((v) => { global_cheat = v; } );
                Promise {
                   <pending>,
                  [Symbol(async_id_symbol)]: 7875,
                  [Symbol(trigger_async_id_symbol)]: 7600,
                  [Symbol(destroyed)]: { destroyed: false }
                }
                > global_cheat
                17
                

                在代码中,这个想法似乎总是强迫人们将“后续”代码放入“then()”部分(或者,如果我理解的话,等效地,放入异步/等待模式,这又是如果我理解,将被重写为“then()”模式)。我想这个想法是这样可以防止“阻塞”系统,尽管在我看来没有提供同步获取值的后门似乎过于家长式的语言设计者。

                注意,再次从交互式命令行:

                > xyz=null; promise.then((v) => {xyz = v;}); console.log(`xyz=${xyz}`);
                xyz=null
                

                这是因为“then()”中的代码还没有运行。

                但是,在“下一行”(在交互式提示处)可以这样做:

                > xyz
                17
                

                【讨论】:

                  【解决方案12】:

                  我觉得这个例子不言自明。注意 await 是如何等待结果的,所以你错过了返回的 Promise。

                  cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
                  Promise {<pending>}
                  cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
                  {publicKey: CryptoKey, privateKey: CryptoKey}
                  

                  【讨论】:

                  • 这必须在异步函数中。
                  【解决方案13】:

                  您可以使用 javascript 中的异步等待方法轻​​松做到这一点。

                  以下是使用超时检索 WebRTC 承诺值的示例。

                  function await_getipv4(timeout = 1000) {
                      var t1 = new Date();
                      while(!window.ipv4) {
                          var stop = new Date() - t1 >= timeout;
                          if(stop) {
                              console.error('timeout exceeded for await_getipv4.');
                              return false;
                          }
                      }
                      return window.ipv4;
                  }
                  
                  function async_getipv4() {
                      var ipv4 = null;
                      var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
                      findIP.then(ip => window.ipv4 = ip);
                      return await_getipv4();
                  };

                  【讨论】:

                  • 重要的是不要在这里运行这个 sn-p,而是在真正的浏览器中运行,我相信这是由于沙盒。
                  • 这会阻塞主线程直到异步返回,首先破坏了使用承诺的对象,不要这样做......
                  猜你喜欢
                  相关资源
                  最近更新 更多