如何在没有"缩进金字塔"的情况下正确表达任意Promise链?

Mai*_*tor 6 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); 
Run Code Online (Sandbox Code Playgroud)

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

const F = (x) => Q.delay(1000).return(x);
Run Code Online (Sandbox Code Playgroud)

在没有生成缩进金字塔的情况下,我无法想到表达该模式:

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)
          )
        )
      )
    )
  )
);
Run Code Online (Sandbox Code Playgroud)

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

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));
Run Code Online (Sandbox Code Playgroud)

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

T.J*_*der 4

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

  1. 做你已经做过的事

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

  3. 将整个事物传递给一个带有ab、 等属性的对象

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


async/await是几年后在这里执行此操作的方法(可能是在问题发布时,提案完成并且它们可以与转译器一起使用时),请参阅Sterling 的答案以了解他们如何简化它。这是一个工作示例:

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);
})()
.catch(error => {
    // ...handle/report error...
});
Run Code Online (Sandbox Code Playgroud)

对于那些环境过时的人来说,可以使用 Babel 的 REPL 来生活。