如何获得承诺的价值?


146

我正在从Angular的文档中查看此示例,$q但我认为这可能总体上适用于Promise。下面的示例从他们的文档中逐字复制,并包含注释:

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就是一个类型为Promise的对象Object。这不是一个Number。那么,它们的含义是“其值将是promiseA的结果加1”?

我应该以这种方式访问promiseB.value吗?成功回调如何返回承诺并返回“结果+ 1”?我想念一些东西。


我问了一个相关的问题:Promise为什么没有get()函数?
罗兰

1
这回答了你的问题了吗?如何从异步调用返回响应?
异端猴子

这个问题有5岁了,并且有一个公认的答案...
临时用户名

@temporary_user_name:人们可以随时投票,即使是对旧问题也可以投票。
半夜

Answers:


141

promiseAthen函式会传回新的promise(promiseB),promiseA该函式在解析后会立即解决,其值就是内从Success函数传回的值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,因为我们已经使用来对promiseA的结果进行了包装await,您可以直接使用它。

但是,await只能在async函数内部使用。因此,要略微缩小,必须包含以上内容:

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

2
理论上,承诺是他们自己的对象。它们包含可以通过promise的成功函数访问的结果。
Nachshon Schwartz

2
因此,如果要使用promise的异步回调的返回值,则必须在另一个异步回调中完成。说得通。我一直在寻找一种获取最终原始返回值的方法,但是我想这会在给定上下文的情况下违背理性。
临时用户名

2
实际上,@ Aerovistae,ES6引入了使之成为可能的生成器,而ES7引入了异步函数-两者都为您提供了超出承诺的语法糖,使它看起来像同步代码(通过在后台运行状态机)-因此请紧紧:)
本杰明·格伦鲍姆

25

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

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;
});

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


4

.thenpromiseB函数接收从.thenpromiseA函数返回的内容。

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


3

分析注释与您当前的理解有所不同可能会有所帮助:

// 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
});

2

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

但是,有一种方法可以通过使用以下不受支持的内部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


1

我发现这个例子不言自明。请注意等待如何等待结果,因此您错过了返回的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}

这必须在异步函数中。
Samed

0
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
}

1
尽管此代码可以回答问题,但提供有关如何以及为什么解决问题的其他上下文将提高答案的长期价值。
亚历山大

0

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


重要的是不要在此处运行此代码段,而应在实际的浏览器中运行,我相信这是由于沙箱。
OxFEEDFACE

0

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

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例如,然后准备使用该变量。当然,对于异步函数之外的脚本中的任何代码,当然都不希望依靠正在解析的异步函数。


0

上面有一些不错的答案,这是ES6 Arrow函数版本

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

0

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

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

await表达式使异步功能的执行暂停,直到Promise被解决(即已实现或拒绝),并在实现后恢复执行异步功能。恢复后,await表达式的值即为已实现的Promise的值如果Promise被拒绝,则await表达式将抛出被拒绝的值。”

MDN Web文档上阅读有关等待承诺的更多信息


-5

也许这个小的Typescript代码示例会有所帮助。

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

这里repository.get(id)返回一个Promise<Account>。我把它赋值给变量account的范围内then声明。


1
您的代码在解决未决问题之前正在返回帐户,这就是为什么它被否决,您的代码始终返回Account.empty();的原因。
Felype '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.