Javascript 如何从承诺中提取数据

Javascript 如何从承诺中提取数据,javascript,promise,ecmascript-6,bluebird,es6-promise,Javascript,Promise,Ecmascript 6,Bluebird,Es6 Promise,我承诺返回数据,我想将其保存在变量中。这在JavaScript中是否因为异步性质而不可能实现?我是否需要使用onResolve作为回调 我是否可以使用它(例如,用async/await包装): const { foo, bar } = Promise.then(result => result.data, errorHandler); // rest of script 而不是这个? Promise.then(result => { const { foo, bar } =

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

不,您不能像示例中建议的那样从Promise同步获取数据。数据必须在回调函数中使用。或者,在函数式编程风格中,promise数据可以是

如果您可以使用(您应该觉得它很棒),那么您可以编写看起来同步的代码,同时保留承诺的异步性(请参阅@loganfsmyth注释)

总的来说,由于您已经在使用ES6,我假设您也在使用transpiler。在这种情况下,您肯定应该尝试一下async/wait
只需确保考虑到目前为止它们还不是一个已批准的规范这一决定。

虽然您可以从异步函数中等待的承诺中获取值(仅仅因为它暂停函数以等待结果),但您永远无法直接从承诺中获取值并返回到与承诺本身相同的范围

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

也就是说,时间旅行。即使时间旅行是可能的,它也可能不是一个好的编码实践,因为时间旅行可能非常令人困惑

一般来说,如果你觉得自己需要这样做,这是一个很好的迹象,你需要重构一些东西。请注意,您在这里对“result=>result.data”所做的操作:

…已经是您通过将值传递给函数来处理(字面上是映射)值的情况。但是,假设“//rest of script”执行了与该值相关的重要操作,您可能希望继续使用另一个函数映射现在更新的值,然后对该值执行一些副作用(如在屏幕上显示数据)


“doSomethingWithData”将在将来的某个未知点被调用(如果调用过的话)。这就是为什么清晰地将所有行为封装到特定函数中,然后将该函数连接到承诺链是一个好的实践

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

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

const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program
你认为那里会发生什么?有两种可能性,但都不好

  • 您的整个程序将停止并等待承诺执行 在它知道“foo”和“bar”会是什么之前。。。不,可能是。(这是 异步函数中的“wait”实际上做的是:它暂停 整个函数执行,直到值可用或抛出错误为止)
  • foo和bar只是没有定义(这就是实际情况) 因为,当同步执行时,它们只是 顶级承诺对象(本身不是“值”)的不存在属性 而是一个准一元包装器,用于获取最终值或错误),这是最重要的 可能还没有包含值

  • 使用javascript是可能的。您可以将在promise success上收到的数据分配给前面声明的变量。您的变量将具有从promise获得的值。你可以参考:你来了@SandipNirmal这是可能的,但可能会导致错误,因为JavaScript不会等待承诺的解决。还需要将
    const
    更改为
    let
    ,这可能会产生副作用。仅供参考,
    errorHandler
    在这里并不真正处理错误,它只是执行immediately@RGraham这种语法在bluebird.js实现中运行良好。根据@zeroflagL async的阻塞性并不比回调更大,可以看出它也是正确的。线程可以自由地处理其他内容(即,如果在NodeJS中有新的请求),而一旦承诺得到解决,执行就会恢复。这只是一种不同的语法。处理程序中的下游代码不会执行,但线程将被释放。所以浏览器不会冻结。现在,如果函数在其顶层使用
    wait
    ,但下游代码执行其他不需要
    async
    函数返回的数据的操作,则这是一个设计错误。如果线程被同步操作阻塞,则会使浏览器冻结。与回调相比,
    async/await
    不会发生这种情况。正如您所说的,它只是一个sugar,但在幕后它的效果是一样的。@zeroflagL如果您不正确,async/await不会阻塞,它将执行异步函数直到第一个
    await
    ,然后暂停异步函数的执行,并将控制返回到父作用域并返回一个承诺。当传递给wait的值可用时,函数将继续执行。“阻止执行和暂停执行之间有一个重要的区别。”洛甘斯迈思说,我感到很羞愧。我刚刚意识到我忘记了一个要点:您只能在异步函数中等待。我脑子里有规则的函数,它们是同步的,因此会阻塞。我也有同样的问题。我理解异步问题。如果我需要一个异步函数来使用,我很难得到的是如何让同步函数等待异步函数
    Promise.then(result => result.data, errorHandler);
    // rest of script
    
    Promise
        .then(result => result.data)
        .then(data => doSomethingWithData)// rest of script
        .catch(errorHandler);
    
    const { foo, bar } = Promise.then(result => result.data, errorHandler);
    console.log(foo);
    //...more program