如何从Promise中提取数据

Tob*_*ühl 16 javascript promise ecmascript-6 bluebird es6-promise

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

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

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

而不是这个?

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

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

sil*_*min 23

不,你不能像你在你的例子中建议的那样同步地获取数据.必须在回调函数中使用该数据.或者在函数式编程风格中,可以对promise数据进行map()编辑.

如果您可以使用async/await(它应该很棒),那么您可以编写看起来同步但保留promise的异步性的代码(请参阅@loganfsmyth注释).

const { foo, bar }  = await iAmAPromise.then(result => result.data);
Run Code Online (Sandbox Code Playgroud)

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

  • @zeroflagL你是不正确的,async/await没有阻塞,它将执行async函数直到第一个`await`然后暂停async函数的执行并将控制返回到父作用域并返回一个promise.当传递给await的值可用时,将继续执行该函数.阻止和暂停执行之间存在重要区别. (3认同)
  • @loganfsmyth 我真丢脸。我刚刚意识到我忘记了一个重要的一点:你只能在异步函数中使用“await”。我想到的是常规函数,它们是同步的,因此会阻塞。 (3认同)
  • _“太棒了”_从什么时候开始阻塞变得很棒了? (2认同)
  • 是的,你不能全局“等待”,只能在可以暂停和恢复的函数的上下文中(因为这只是生成器顶部的糖)。在函数外部,您仍在处理 Promise,并且您无法在该上下文中从 Promise 中“获取”最终值,您只能对其进行 map/flatMap 来处理它。 (2认同)

Dti*_*son 5

虽然您可以从异步函数内的等待的Promise中获取值(仅仅是因为它暂停了该函数以等待结果),但您永远无法直接从Promise中获取值并返回到与Promise本身相同的作用域中。

这是因为“超出”意味着尝试获取将来存在的某些东西(最终解析的值)并将其放入过去已经发生的上下文(同步变量赋值)中。

也就是说,时间旅行。即使时间旅行是可能的,但这也不是一个好的编码习惯,因为时间旅行可能会非常混乱。

通常,如果您觉得自己需要这样做,则表明您需要重构某些东西,这是一个好兆头。请注意,您在此处使用“结果=> result.data”的操作:

Promise.then(result => result.data, errorHandler);
// rest of script
Run Code Online (Sandbox Code Playgroud)

已经通过将...传递给函数来使用.. (实际上是映射)该值。但是,假设“ //脚本的其余部分”做了一些与此值相关的重要事情,您可能想继续使用另一个函数映射到现在更新的值上,然后再对该值做一些副作用(例如显示屏幕上的数据)。

Promise
    .then(result => result.data)
    .then(data => doSomethingWithData)// rest of script
    .catch(errorHandler);
Run Code Online (Sandbox Code Playgroud)

将来会在某个未知点调用“ doSomethingWithData”(如果曾经被调用过)。这就是为什么最好将所有行为明确封装到特定功能中,然后将该功能挂接到Promise链上的原因。

说实话,这是更好的方法,因为它要求您明确声明将要发生的特定事件序列,与所有应用程序代码执行的第一次运行明确地分开。

换句话说,假设此场景假设在全局顶级范围内执行:

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

您希望在那里发生什么?有两种可能性,并且两者都是不好的。

  1. 整个程序就必须要停止,等待承诺执行,才能够知道什么是“富”与“酒吧”将......不,可能是。(这实际上是异步函数中的“等待”操作:它会暂停整个函数执行,直到该值可用或抛出错误为止)
  2. foo和bar只是不确定的(实际上就是这样),因为在同步执行时,它们只是顶级Promise对象的不存在属性(它本身不是“值”,而是一个准Monadic包装器,以获取最终值或错误),该包装器很可能甚至包含值。