问题 如何从Promise中提取数据


我有一个承诺,返回数据,我想将其保存在变量中。这在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。


7572
2018-04-28 09:59


起源

这可以用javascript。您可以将承诺成功时收到的数据分配给之前声明的变量。并且您的变量将具有您从承诺中获得的价值。你可以参考: developer.mozilla.org/en/docs/Web/JavaScript/Reference/... - Sandip Nirmal
async/ await 来了! - Paul Stenne
@SandipNirmal这是可能的,但可能会导致错误,因为JavaScript不会等待Promise解析。还需要改变 const 至 let,这可能有副作用。 - Tobias Mühl
仅供参考, errorHandler 这里没有真正处理错误,它只是立即执行 - CodingIntrigue
@RGraham这个语法与bluebird.js实现一起正常工作。看到 bluebird API在这里引用 这也是正确的 承诺/ A +标准(见第2.2段) - Tobias Mühl


答案:


不,你无法获得数据 同步 出于你在你的例子中建议的承诺。数据必须在回调函数中使用。或者在函数式编程风格中,promise数据可以是 map()编辑

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

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

总的来说,因为你已经在使用ES6,我假设你也在使用一个转换器。在这种情况下,你一定要给 异步/ AWAIT 一试。 请务必在决定中重视,因为今天他们还没有批准的规范。


13
2018-04-28 10:05



@zeroflagL async并不比promises回调阻塞更多。线程可以自由地处理其他内容(即NodeJS中的新请求),而执行将在promise解析后恢复。这只是一种不同的语法。 - silkAdmin
处理程序中的下游代码不会执行,但线程将被释放。所以浏览器不会冻结。现在,如果函数使用 await 在它的顶层,但下游代码执行其他操作,不需要返回的数据 async 功能那么这是一个设计错误。 - silkAdmin
如果线程被同步操作阻止,浏览器冻结的原因是什么。哪个不会发生 async/await 不仅仅是回调。就像你说它只是糖,但在幕后它的效果是一样的。 - silkAdmin
@zeroflagL你是不正确的,async / await没有阻塞,它会执行async函数直到第一个 await 然后暂停执行异步函数并将控制返回到父作用域并返回一个promise。当传递给await的值可用时,将继续执行该函数。阻止和暂停执行之间存在重要区别。 - loganfsmyth
@loganfsmyth对我感到羞耻。我才意识到我忘记了一个重点:你只能这样做 await 在异步函数中。我有常规的功能,这将是同步的,因此会阻止。 - a better oliver


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

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

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

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

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

..是 已经 您通过将值传递给函数来处理(字面上,映射)值的情况。但是,假设“//脚本的其余部分”执行与此值相关的重要事项,您可能希望这样做 继续 使用另一个函数映射现在更新的值,然后使用该值执行side-effect-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. 你的整个程序(console.log以及之后发生的一切) 它会  停止并等待Promise执行 在它知道“foo”会是什么之前......不, 威力 是。 (这是 异步函数中的“await”实际上是做什么的:它暂停了 整个函数,直到值或错误返回)
  2. foo和bar只是未定义(这实际上就是这样     发生),因为,同步执行,他们只是     Promise对象不存在的属性(不是值,     但是Monad包含最终值或错误)     可能甚至没有包含值。

2
2018-04-29 19:39