在处理递归时,使用Promises来减少模式有什么选择?

时间:2019-08-12 10:05:28

标签: javascript promise es6-promise

注意:我不能使用async

在需要遍历数组并对其成员执行相同功能并返回Promise的情况下,我喜欢使用reduce模式,例如:

function get_count() {
  return new Promise(function(resolve, reject) {
    resolve(3);
  });
}

function recursively_execute(data) {
  return new Promise(function(resolve, reject) {
    resolve(data);
  });
}

function reduce_promise_pattern() {

  const get_batch_run_count = get_count();

  const batch_process = get_batch_run_count.then((count_value) => {

    const run_count = new Array(count_value).fill('batch');

    function recursive_function(data) {
      console.log('Running batch!');
      return recursively_execute(data).then(() => {
        return data;
      });
    }

    return run_count.reduce((previous_promise) => {
      return previous_promise.then((previous_response) => {
        test_data = {
          'test': 1
        };
        return recursive_function(test_data);
      })
    }, Promise.resolve())
  });
  return batch_process;
}

这将运行3次,因为run_count基本上会构建3个元素的数组。尽管可以,但是对我来说这就像是一个hack。

当我的列表已经预先定义了唯一项并且这些项单独使用时,这种方法就可以使用了,例如,如果我有3个步骤,则可以在内部单独使用,将其减少为基于的数据要经历的这三个步骤都是唯一的,并且每一步的数据将在一次运行中使用...但是就我而言?我只是在欺骗系统,使他们认为这些是不同的项目。

有什么替代方法?

2 个答案:

答案 0 :(得分:3)

您已达到Promise链的极限,尽管它们无法读取,但它们的工作原理。这就是为什么引入async / await来处理这些用例的原因,有了它们,您可以停止各种(嵌套的)循环,而不必为每个用例维护承诺。

 async function reducePromisePattern() {
   for(let i = await getCount(); i >= 0; i--) {
     await recursiveFunction({'test': 1 });
   }
 }

如果您不能使用/转换async,您仍然可以编写一些小助手来为您执行循环,例如:

 function loopAsync(times, fn) {
   function task() {
    times--;
    if(times <= 0) return;
    return fn().then(task);
   }

   return Promise.resolve().then(task);
 }

 function reducePromisePattern() {
   return getCount().then(function(count) {
      return asyncLoop(count, function() {
         return recursiveFunction({ test: 1 });
      });
   });
 }   

答案 1 :(得分:0)

这里有两个选项,彼此之间没有嵌套功能。第一个函数仅使用for循环,而第二个函数使用递归解决方案。两种解决方案的最后一个参数都是可选的,并且仅在要将返回数据从一次运行传递到下一次运行时才使用(类似于reduce)。

const sleep = () => new Promise(resolve => setTimeout(resolve, Math.random() * 1500 + 500));

// solution #1 - for-loop
function times1(n, callback, init) {
  var promise = Promise.resolve(init);
  
  for (; n > 0; --n) {
    promise = promise.then(val => callback(val));
  }
  
  return promise;
}

// example usage
times1(3, n => {
  console.log("solution #1 -", n);
  return sleep().then(() => n + 1);
}, 0);


// solution #2 - recursive
function times2(n, callback, init) {
  var promise = Promise.resolve(init);
  
  if (n <= 0) return promise;
  return promise.then(val => times2(n - 1, callback, callback(val)));
}

// example usage
times2(3, n => {
  console.log("solution #2 -", n);
  return sleep().then(() => n + 1);
}, 0);