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



我很难解决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应该接受一个函数数组,通过then按顺序调用它们,并返回一个使用最终函数的返回值解析的 Promise。

这是我最终找到的解决方案:

const reduce = (fns, init) => {
return new Promise(resolve => {
fns.concat([resolve]).reduce((prev, cur) => prev.then(cur), init)
})
}

嗯...正如我在评论中提到的,您有一个有趣的问题,它需要将同步代码与异步代码混合在一起,但它可以通过某种方式实现......

我可能会想出如下解决方案;

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)));

这是完整的:

// *** 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));

在某些情况下,将最终函数附加到函数数组中并允许它由 reduce 处理可能更方便:

// *** 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(...)的需求,这通常仅在承诺接受回调的函数时是预期的。

最新更新