如何从Promise中提取数据

问题描述 投票:12回答:2

我有一个返回数据的承诺,我希望将其保存在变量中。由于异步性质,这在JavaScript中是不可能的吗?我需要使用onResolve作为回调吗?

我可以以某种方式使用它(例如用async / await包装它):

const { foo, bar } = Promise.then(result => result.data, errorHandler);
// rest of script

而不是这个?

Promise.then(result => {
   const { foo, bar } = result.data;
   // rest of script
 }, errorHandler);

注意:使用Bluebird库而不是本机实现,我无法从Promise更改为asnyc / await或Generators。

javascript promise ecmascript-6 bluebird es6-promise
2个回答
22
投票

不,你不能像你在你的例子中建议的那样同步地获取数据。必须在回调函数中使用该数据。或者在函数式编程风格中,承诺数据可以是map()ed over

如果你可以使用async/await(你应该很棒),那么你可以编写看起来同步的代码但保留promise的异步性(参见@loganfsmyth comments)。

const { foo, bar }  = await iAmAPromise.then(result => result.data);

总的来说,因为你已经在使用ES6,我假设你也在使用一个转换器。在这种情况下你绝对应该尝试async / await。请务必在决定权重,因为今天他们还没有批准的规范。


5
投票

虽然你可以在async函数中从一个等待的Promise中获取一个值(只是因为它暂停了等待结果的函数),但你不能直接从Promise中获取一个值并返回到与Promise本身相同的范围内。 。

这是因为“out of”意味着尝试采用未来存在的东西(最终解决的值)并将其置于过去已经发生的上下文(同步变量赋值)中。

也就是时间旅行。即使时间旅行是可能的,它也可能不是一个好的编码实践,因为时间旅行可能会非常混乱。:)

一般来说,如果你发现自己感觉需要这样做,那么你需要重构某些东西是个好兆头。请注意你在这里使用“result => result.data”做的事情:

Promise.then(result => result.data, errorHandler);
// rest of script

..已经是你通过将值传递给函数来处理(字面意思,映射)值的情况。但是,假设“//脚本的其余部分”执行与此值相关的重要事项,您可能希望继续使用另一个函数映射现在更新的值,然后使用该值执行副作用y(如显示屏幕上的数据)。

Promise
    .then(result => result.data)
    .then(data => doSomethingWithData)// rest of script
    .catch(errorHandler);

将来会在某个未知点调用“doSomethingWithData”(如果它曾被调用过)。这就是为什么将所有行为清楚地封装到特定函数中然后将该函数挂钩到Promise链是一个好习惯。

老实说,这种方式更好,因为它要求您清楚地声明将要发生的特定事件序列,从第一次运行中明确地分离出所有应用程序代码的执行。

换句话说,想象一下这个场景,假设在全局顶级范围内执行:

const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program

你期望在那里发生什么?有两种可能性,它们都很糟糕。

  1. 你的整个程序必须暂停并等待Promise执行才能知道“foo”和“bar”会是什么......不管怎么样。 (这是异步函数中的“等待”,实际上确实这样做:它暂停整个函数执行,直到值可用或抛出错误)
  2. foo和bar只是未定义(这是实际发生的事情),因为,如同步执行,它们只是顶级Promise对象的不存在的属性(它本身不是“值”,而是一个获得最终值或错误的准Monadic包装器,其中很可能甚至不包含值。
© www.soinside.com 2019 - 2024. All rights reserved.