reduce()一个Promises数组,将每个Promise的返回值传递给下一个

时间:2017-09-21 17:46:56

标签: javascript promise reduce

我无法解决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。

3 个答案:

答案 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(...)的需要,这通常只有在宣传带回调的函数时才会出现。