有一些方法,例如Q.reduce
和Q.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
不在第二行的范围内。处理这种情况的正确方法是什么?
答案 0 :(得分:3)
由于后续操作依赖于先前操作的多个位,您的选择是:
做你做过的事
将变量放在链外并随时分配
让整个事物绕过一个带有a
,b
的对象,并将其作为属性
#1是我坚持的,除非真的有充分的理由去做其他两个中的任何一个。幸运的是,这种积累很少像你的问题所示那么深。
如果您希望提前采用async
/ await
(the 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
不幸的是,您可能需要向下调整以供一般使用,输出可能会变得非常大。