我怎样才能获得承诺的价值

How can I access the value of a promise?

本文关键字:承诺      更新时间:2023-09-26

我正在查看 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 类型的 promise 对象。这不是Number.那么,"它的价值将是 promiseA 增加 1 的结果"是什么意思呢?

我应该将其作为promiseB.value或类似的东西访问吗?成功回调如何返回承诺并返回"结果 + 1"?我错过了一些东西。

promiseAthen 函数返回一个新的 promise(promiseB(,该 promise 在解析后立即解析promiseA,其值是 promiseA 内从成功函数返回的值。

在这种情况下,promiseA使用值 - result 解析,然后立即使用 result + 1 的值解析promiseB

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

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

从 ECMAScript 2016 (ES7, 2016( 开始,async/await 是 JavaScript 的标准,它允许使用上述方法的替代语法。您现在可以编写:

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

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

但是,await只能在async函数中使用。因此,要稍微缩小,必须像这样包含上述内容:

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

而且,为了清楚起见,此示例中doSomething函数的返回值仍然是一个承诺 - 因为异步函数返回承诺。因此,如果您想访问该返回值,则必须执行result = await doSomething(),这只能在另一个异步函数中执行。基本上,只有在父异步上下文中,才能直接访问从子异步上下文生成的值。

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

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

then 方法还返回一个 promise:promiseB,它将根据 promiseA 的成功/错误处理程序的返回值进行解析/拒绝。

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

  1. 不返回任何内容→承诺B立即解决,和未定义被传递给 promiseB 的成功处理程序
  2. 返回一个值→ PromiseB 立即解析,并将值传递给 promiseB 的成功处理程序
  3. 返回承诺→解决后,承诺 B 将被解析。当被拒绝时,承诺B将被拒绝。传递给的值承诺 B 的 then 处理程序将是承诺的结果

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

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

然后调用立即返回 promiseB。

解析 promiseA 后,它会将结果传递给 promiseA 的成功处理程序。

由于返回值是 promiseA 的结果 + 1,因此成功处理程序返回一个值(上面的选项 2(,因此 promiseB 将立即解析,而 promiseB 的成功处理程序将传递 promiseA 的结果 + 1。

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

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

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

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

  • 文档:文档弃用 Process.binding #22004

  • 从进程绑定迁移 #22064

之前有一些很好的答案,这里是 ES6 箭头函数版本:

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

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

这里 promiseA 返回一个数字,该数字将作为 promiseB 成功函数中的number参数。然后递增 1。

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

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

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

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

等待 (MDN(:

await 表达式会导致异步函数执行暂停,直到 Promise 结算(即履行或拒绝(,并在履行后恢复异步函数的执行。恢复时,等待表达式的值是已实现承诺的值。

如果承诺被拒绝,await 表达式将抛出拒绝的值

在 MDN Web 文档中阅读更多关于等待和承诺的信息。

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

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

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

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

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

这使您在运行脚本并访问设置变量后进入 Node.js REPL。例如,若要确认异步函数已返回,可以记录connection,然后就可以使用该变量了。当然,对于异步函数之外的脚本中的任何代码,人们不希望指望异步函数正在解析异步函数。

在交互式提示下进行实验时,可以通过将值分配给 "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

MDN 文档帮助我解决了这个问题:

Promise.resolve((

let promiseB = promiseA;
promiseB.then((value) => {
    console.log(value);
});

如果需要向下访问 JSON 对象的多个级别:

let promiseB = promiseA;
promiseB.then((value) => {
    console.log(value?.key1.key2);
});
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
}

这个例子我觉得不言自明。请注意等待如何等待结果,因此您错过了返回的承诺。

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}

你可以在 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();
};