如何正确表达任意Promise链而没有"缩进金字塔"?

时间:2017-01-16 18:02:58

标签: javascript promise bluebird

有一些方法,例如Q.reduceQ.all,有助于在承诺的异构集合的特定情况下展平承诺链。但是,请注意通用案例:

const F = (x) => x;
const a = F(1);
const b = F(2);
const c = F(a + b);
const d = F(a + c);
const e = F(b + c);
console.log(e); 

即,每个术语依赖于任意先前定义的术语的一系列赋值。假设F是异步调用:

const F = (x) => Q.delay(1000).return(x);

在没有生成缩进金字塔的情况下,我无法思考这种模式:

F(100).then(a =>
  F(200).then(b =>
    F(a+b).then(c =>
      F(a+c).then(d =>
        F(b+c).then(e =>
          F(d+e).then(f =>
            console.log(f)
          )
        )
      )
    )
  )
);

请注意,使用返回的值不起作用:

F(100).then(a => F(200))
    .then(b => F(a+b))
    .then(c => F(a+c))
    .then(d => F(b+c))
    .then(e => F(d+e))
    .then(f => console.log(f));

例如,因为a不在第二行的范围内。处理这种情况的正确方法是什么?

3 个答案:

答案 0 :(得分:3)

由于后续操作依赖于先前操作的多个位,您的选择是:

  1. 做你做过的事

  2. 将变量放在链外并随时分配

  3. 让整个事物绕过一个带有ab的对象,并将其作为属性

  4. #1是我坚持的,除非真的有充分的理由去做其他两个中的任何一个。幸运的是,这种积累很少像你的问题所示那么深。

    如果您希望提前采用async / awaitthe proposal已完成,那么它们将在ES2017中,您现在可以使用它们一个转换器),然后看Sterling's answer它们如何简化它。这是一个工作示例(live on Babel's REPL):

    const F = x => {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(x);
        }, 100);
      });
    };
    (async () => {
      const a = await F(100);
      const b = await F(200);
      const c = await F(a+b);
      const d = await F(a+c);
      const e = await F(b+c);
      const f = await F(d+e);
      console.log(f);
    })();
    

答案 1 :(得分:3)

第二次尝试。 JS聊天中的@Luggage建议使用Async / Await来保持你的参数范围。

let a = await F(200);
let b = await F(a + 100);
let c = await F(a + b);
//... etc, all inside an async function

你也可以使用Promise.all或(这是我的经验)我已经使用async lib来帮助解决这些问题。

async.waterfall([
   (callback) => {
        let a = F(200);
        callback(null, a)
    }, (a, callback) => {
        let b = F(a+b);
        callback(null, b);
    }, //etc down the chain
]);

我认为Promise.all会比异步lib更好地管理它,但async / await是这里最漂亮的方法,尽管它需要ES2017支持/转换。

答案 2 :(得分:2)

Async / await我认为很好地解决了这个问题;

async function runAsync(){
  const F = async (x) => x;
  const a = await F(1);
  const b = await F(2);
  const c = await F(a + b);
  const d = await F(a + c);
  const e = await F(b + c);
  console.log(e);
}

function runSync(){
  const F = (x) => x;
  const a = F(1);
  const b = F(2);
  const c = F(a + b);
  const d = F(a + c);
  const e = F(b + c);
  console.log(e);
}

runSync(); //5
runAsync(); //5

这将使用node --harmony-async-await example

在节点7本地运行

不幸的是,您可能需要向下调整以供一般使用,输出可能会变得非常大。