简体   繁体   English

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

[英]reduce() an array of Promises, passing the return value of each to the next

I'm having trouble wrapping my head around a certain problem with Promises. 我在解决Promises的某个问题时遇到了麻烦。 I need to take a dynamic array of functions, some of which may return Promises, and call them sequentially using .then . 我需要获取一个动态的函数数组,其中一些函数可能返回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}
]

What I'm looking for is basically a reduce function that I can use like this: 我正在寻找的基本上是一个可以像这样使用的reduce函数:

Promise.resolve({name, data}).then(reduce(fns)).then(({name, data}) => doSomething(name, data))

So reduce should take an array of functions, call them sequentially passing the return value of the last via then , and return a Promise that resolves with the return value of the final function. 因此, reduce应该采用一个函数数组,依次调用它们, then通过then传递最后一个函数的返回值,并返回一个Promise,该函数以最终函数的返回值进行解析。

Here's the solution I eventually found: 这是我最终找到的解决方案:

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

Well... as i have mentioned in my comment you have an interesting to question which requires to mix up synchronous code with asynchronous yet it is doable by some means... 好吧...正如我在评论中提到的那样,您有一个有趣的问题要解决,那就是将同步代码与异步代码混合在一起,但是通过某种方式是可行的...

I might come up with a solution as follows; 我可能会提出以下解决方案;

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

Here it is in full : 这是完整的:

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

or, more compactly : 或者,更紧凑地说:

// *** 2 ***
const initialVal = {name:'x', data:'y'};
fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(initialVal))
.then(({name, data}) => doSomething(name, data));

Or, for reusability you might choose to encapsulate the reduction in a function, say doAsyncSequence() , and pass in the array of functions and the initial value. 或者,为了实现可重用性,您可以选择将简化形式封装在一个函数中,例如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));

Under certain cirumstances it might be more convenient to append the final function to the array of functions and allow it to be handled by the reduction : 在某些情况下,将最终函数追加到函数数组中并允许由归约法处理可能会更方便:

// *** 4 ***
// with #3 in place
const myFinalFunction = ({name, data}) => doSomething(name, data);
const initialVal = {name:'x', data:'y'};
doAsyncSequence(fns.concat(myFinalFunction), initialVal);

Your own solution, which attempts to do the same as #3, has a flaw. 您自己的尝试与#3相同的解决方案有一个缺陷。 If init is not thenable, then it will throw synchronously at the first iteration of the reduction. 如果init不thenable,那么它将在同步减少的第一次迭代扔。 All the solutions above avoid that issue by ensuring with Promise.resolve(initialValue) that the start value is a promise, and avoids the need for new Promise(...) , which is generally expected only when promisifying functions that take callbacks. 上面的所有解决方案都通过Promise.resolve(initialValue)来确保起始值是一个承诺,从而避免了该问题,并且避免了对new Promise(...) ,通常只有在使带有回调的函数混杂时才期望这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM