如何访问承诺的价值?

How to access the value of a promise?

我正在查看 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。那么 "its value will be the result of promiseA incremented by 1" 是什么意思?

我应该以 promiseB.value 或类似的方式访问它吗?成功回调return promise AND return "result + 1" 怎么可能?我错过了一些东西。

promiseAthen函数returns一个新的promise(promiseB)在promiseA被resolved之后立即被resolved,它的值是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;
}

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

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

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

// promiseB will be resolved immediately after promiseA is resolved

这说明 promiseB 是一个承诺,但会在 promiseA 解决后立即解决。另一种看待这个的方式意味着 promiseA.then() returns 一个分配给 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
});

当承诺为 resolved/rejected 时,它将调用其 success/error 处理程序:

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

then 方法也 return 是一个承诺:promiseB,它将是 resolved/rejected 取决于 return 来自 [=27] 的值=] 来自 promiseA.

的处理程序

promiseA 的 success/error 处理程序可以 return 三个可能的值来影响 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;
});

然后立即调用 returns promiseB。 当 promiseA 被解析时,它会将结果传递给 promiseA 的成功处理程序。 由于 return 值是 promiseA 的结果 + 1,成功处理程序是 returning 一个值(上面的选项 2),因此 promiseB 将立即解析,并且 promiseB 的成功处理程序将传递给 promiseA 的结果 + 1。

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
}

您可以使用 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();
};

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

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

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

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

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

这个例子我觉得不言自明。请注意 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}

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

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

带有 await 的行通常 return 是一个承诺。此代码可以粘贴到节点 REPL 中,或者如果保存在 index.js 中,它可以是 运行 in Bash with

node -i -e "$(< index.js)"

在 运行 脚本访问 set 变量后,您将留在 Node REPL 中。要确认异步函数已 returned,您可以记录 connection 例如,然后您就可以使用该变量了。对于异步函数之外的脚本中的任何代码,当然不希望依赖正在解析的异步函数。

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

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

我对 javascript promises 的学习很慢,默认情况下所有异步函数 return 一个 promise,您可以将结果包装为:

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

"await 表达式导致异步函数执行暂停,直到 Promise 被解决(即完成或拒绝),并在完成后恢复执行异步函数。恢复时,值await 表达式的是 fulfilled Promise 的表达式。 如果 Promise 被拒绝,await 表达式将抛出被拒绝的值 ."

详细了解 await and promises at MDN 网络文档

在交互式提示下进行实验时,可以通过将值分配给“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()”部分(或者,如果我理解的话,等效地放入 async/await 模式,如果我理解的话,它又被重写为“then()”模式)。我想这个想法是这样可以防止“阻塞”系统,尽管不提供后门来同步获取值在我看来是语言设计者的过度家长式作风。

请注意,再次来自交互式命令行:

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

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

但是,在“下一行”(在交互式提示符处),可以执行以下操作:

> xyz
17

实际上,从交互式 (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 }
}