如何在没有 "indentation pyramids" 的情况下正确表达任意 Promise 链?
How to correctly express arbitrary Promise chains without "indentation pyramids"?
有 Q.reduce
和 Q.all
等方法可以帮助在异类 promise 集合的特定情况下展平 promise 链。不过请注意,一般情况:
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
不在第二行的范围内。处理这种情况的正确方法是什么?
由于后续操作依赖于先前操作的多个位,您的选择是:
做你做过的事
把变量放到链外,边走边赋值
让整个对象绕过一个带有 a
、b
等属性的对象
#1 是我会坚持的,除非 真的 有很好的理由去做其他两个。幸运的是,这种积累很少像你的问题那样深入。
async
/await
是几年后在这里做的方法(并且可能是在问题发布时,the proposal was finished and they could be used with a transpiler), see 他们如何简化它。这是一个工作示例:
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...
});
Live on Babel's REPL 对于环境过时的人。
第二次尝试。 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
库来帮助解决这些问题。
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
会比异步库更好地管理它,但是 async/await 是这里最漂亮的方法,尽管它需要 ES2017 support/transpiling.
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
不幸的是,您可能需要向下编译以供一般使用,并且输出可能会变得非常大。
有 Q.reduce
和 Q.all
等方法可以帮助在异类 promise 集合的特定情况下展平 promise 链。不过请注意,一般情况:
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
不在第二行的范围内。处理这种情况的正确方法是什么?
由于后续操作依赖于先前操作的多个位,您的选择是:
做你做过的事
把变量放到链外,边走边赋值
让整个对象绕过一个带有
a
、b
等属性的对象
#1 是我会坚持的,除非 真的 有很好的理由去做其他两个。幸运的是,这种积累很少像你的问题那样深入。
async
/await
是几年后在这里做的方法(并且可能是在问题发布时,the proposal was finished and they could be used with a transpiler), see
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...
});
Live on Babel's REPL 对于环境过时的人。
第二次尝试。 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
库来帮助解决这些问题。
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
会比异步库更好地管理它,但是 async/await 是这里最漂亮的方法,尽管它需要 ES2017 support/transpiling.
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
不幸的是,您可能需要向下编译以供一般使用,并且输出可能会变得非常大。