调用一个数组函数,按顺序返回promises,没有外部依赖

时间:2016-11-19 05:18:25

标签: javascript node.js promise

不使用任何额外的库(async,bluebird等)我试图实现一个函数,它返回一个promise,它根据一个函数数组来解析(或拒绝),这些函数将promises作为一个函数返回输入参数... Promise.all(iterable)具有与我要完成的功能非常相似的功能,但iterable Promise.all参数中的承诺不按顺序执行。

我可以简单地将这些功能链接在一起,但如果functionList是未知长度的列表,那该怎么办...

我已尝试在概念上展示我在下面要完成的任务:

function foo() {
  return new Promise((resolve, reject) => {
    setTimeout( () => {
        return resolve();
       }, 200);
  })
}

function bar() {
  return new Promise((resolve, reject) => {
    setTimeout( () => {
        return resolve();
       }, 200);
  })
}

function baz() {
  return new Promise((resolve, reject) => {
    setTimeout( () => {
        return reject();
       }, 100);
  })
}

const functionList = [foo, bar, baz];

function promiseSeries(functionList){
    const results = [];
    return new Promise((resolve, reject) => {
      promiseList.map((promise, i) => {
        return new Promise((_resolve, _reject) => {
          promise()
            .then((result) => {
              results.push(result);
              if (i === promiseList.length - 1) {
                return resolve(results);
              }
               else return _resolve();
            })
            .catch(error => error)
        })
      })
    })
  }

显然,在functionList上运行Promise.all,我们会看到baz(即使它的位置是functionList [2] 首先解析

Resolve promises one after another (i.e. in sequence)?Running promises in small concurrent batches (no more than X at a time)都没有提供此问题的答案。我不想导入一个库来处理这个单一的实用程序函数,而且我只是好奇这个函数的样子。

4 个答案:

答案 0 :(得分:1)

这并不比以下更复杂:

funcs.reduce((prev, cur) => prev.then(cur), Promise.resolve())

递归版本,返回已解析值的数组:



function recurse([first, ...last], init) {
  if (!first) return Promise.resolve([]);
  return first(init)
    .then(value => 
      recurse(last, value)
        .then(values => [value, ...values])
    );
}

// Testing function to return a function which
// returns a promise which increments its value.
const x = v => y => Promise.resolve(v + y);
    
recurse([x(1), x(2)], 0).then(console.log);




答案 1 :(得分:0)

最简单的方法是将它们链接起来,从空承诺开始:

const promises = [foo, bar, baz];
let result = Promise.resolve();
promises.forEach(promise => result = result.then(() => promise));
return result;

正如阿里指出的那样,你可以使用减少代替,但你需要在当时的调用中使用函数:

return promises.reduce(
    (result, promise) => result.then(() => promise),
    Promise.resolve()
);

如果你知道promises不为空,你可以省略初始值。

但是如果你真的想按顺序做事,你经常想要处理一系列返回promise的函数。例如:

return ids.map(id => () => processId(id))
.reduce((p, fn) => p.then(fn), Promise.resolve());

答案 2 :(得分:0)

在没有任何额外库的情况下实现此目的的一种很好而且干净的方法是使用递归。一个例子:

const p1 = () => Promise.resolve(10);
const p2 = () => Promise.resolve(20);
const p3 = () => Promise.resolve(30);

const promiseList = [p1, p2, p3];

const sequencePromises = (promises) => {
  const sequence = (promises, results) => {
    if (promises.length > 0) {
      return promises[0]()
        .then(res => sequence(promises.splice(1, promises.length), results.concat(res)))
        .catch(err => Promise.reject(err));
    } else {
      return Promise.resolve(results);
    }
  }
  return sequence(promises, []);
}

sequencePromises(promiseList)
   .then(res => console.log(res))
   .catch(err => console.log("ERROR"));

答案 3 :(得分:-1)

promises.reduce((previous, promise) => {
  if (previous) {
    return previous.then(() => promise);
  }
  return promise;
}, null)