我无法解决Promises的某个问题。我需要一个动态的函数数组,其中一些函数可能会返回Promises,并使用.then
顺序调用它们。
let fns = [
({name, data}) => new Promise((name, data) => {
console.log(name, data)
return {name, data: { ...data, logged: true}}
}),
({name, data}) => ({name: name.toLowerCase(), data}),
({name, data}) => new Promise((name, data) => {
setTimeout((name, data) => someAjaxFunction(name, data), 10000)
return {name, data}
]
我正在寻找的基本上是reduce
函数,我可以这样使用:
Promise.resolve({name, data}).then(reduce(fns)).then(({name, data}) => doSomething(name, data))
所以reduce
应该接受一个函数数组,按顺序调用它们传递最后一个via then
的返回值,并返回一个用最终函数的返回值解析的Promise。
答案 0 :(得分:0)
这是我最终找到的解决方案:
const reduce = (fns, init) => {
return new Promise(resolve => {
fns.concat([resolve]).reduce((prev, cur) => prev.then(cur), init)
})
}
答案 1 :(得分:0)
嗯......正如我在评论中提到的那样,你有一个有趣的问题,需要将同步代码与异步混合,但它可以通过某种方式实现......
我可能会提出如下解决方案;
let fns = [({name, data}) => new Promise((v,x) => { console.log(name, data);
v({name: name, data: data, logged: true});
}),
({name, data}) => ({name: name.toLowerCase(), data: data}),
({name, data}) => new Promise((v,x) => setTimeout((n, d) => v({name: n, data: d, logged: true}), 1000, name, data))
];
var promises = fns.map(function(f){
var res = f({name:"x",data:[1,2,3]}); // some return promise some not
return res.then ? res : Promise.resolve(res); // check if they have a then method
});
Promise.all(promises)
.then(ps => ps.forEach(v => console.log(v)));
答案 2 :(得分:0)
这里是完整的:
// *** 1 ***
const initialVal = {name:'x', data:'y'};
fns.reduce(function(promise, fn) {
return promise.then(fn);
}, Promise.resolve(initialVal))
.then(function({name, data}) {
return doSomething(name, data));
};
或更紧凑:
// *** 2 ***
const initialVal = {name:'x', data:'y'};
fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(initialVal))
.then(({name, data}) => doSomething(name, data));
或者,对于可重用性,您可以选择将减少封装在函数中,比如doAsyncSequence()
,并传递函数数组和初始值。
// *** 3 ***
function doAsyncSequence(fns, initialVal) => {
return fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(initialVal));
}
// call as follows
doAsyncSequence(fns, {name:'x', data:'y'}).then(({name, data}) => doSomething(name, data));
在某些情况下,将最终函数附加到函数数组并允许通过缩减处理它可能更方便:
// *** 4 ***
// with #3 in place
const myFinalFunction = ({name, data}) => doSomething(name, data);
const initialVal = {name:'x', data:'y'};
doAsyncSequence(fns.concat(myFinalFunction), initialVal);
你自己的解决方案,试图像#3一样,有一个缺陷。如果init
不可用,那么它将在缩减的第一次迭代时同步抛出。上面的所有解决方案都通过确保Promise.resolve(initialValue)
启动值是一个承诺来避免这个问题,并且避免了new Promise(...)
的需要,这通常只有在宣传带回调的函数时才会出现。