【问题标题】:Javascript promise recursion and chainingJavascript 承诺递归和链接
【发布时间】:2016-04-01 09:58:28
【问题描述】:

我应该如何编写递归循环以按顺序正确执行 Promise?我试过 Promise.all(Array.map(function(){}));这不适合我的需要,因为这些步骤需要按顺序运行。我已经尝试过自定义承诺,因为我找到了here,但它也有问题。

承诺:

var promiseFor = (function(condition, action, value) {
    var promise = new Promise(function(resolve, reject) {
        if(!condition(value)) {
            return;
        }
        return action(value).then(promiseFor.bind(null, condition, action));
    });
    return promise;
});

这个for的问题是它似乎停在最深的递归调用处,而不是返回继续执行循环以正确完成。

例如:在 PHP 中这样的代码:

function loopThrough($source) {
    foreach($source as $value) {
        if($value == "single") {
            //do action
        } else if($value == "array") {
            loopThrough($value);
        }
    }
}

如果我通过让我们说一个文件夹结构并且“单个”表示文件,它将打印所有文件。但是我使用的承诺在第一个死胡同处停止。

编辑:添加了 bluebird 以查看它是否可以提供任何帮助,但还是一样。 这是当前循环代码

var runSequence = (function(sequence, params) { 
    return Promise.each(sequence, function(action) {
        console.log(action['Rusiavimas'] + ' - ' + action['Veiksmas']);
        if(params.ButtonIndex && params.ButtonIndex != action['ButtonIndex']) {
            return Promise.resolve();
        }

        if(action['Veiksmas'].charAt(0) == '@') {
            var act = action['Veiksmas'];
            var actName = act.substr(0, act.indexOf(':')).trim();
            var actArg = act.substr(act.indexOf(':')+1).trim();

            /* This one is the code that figures out what to do and
               also calls this function to execute a sub-sequence. */
            return executeAction(actName, actArg, params);
        } else {
            sendRequest('runQuery', action['Veiksmas']);
        }
    });
});

我有 3 个序列,每个序列包含 5 个动作。第一个和第二个序列具有下一个序列,因为它是第三个动作。这是我得到的结果(数字表示哪个序列):

1 - @PirmasVeiksmas
1 - @AntrasVeiksmas
1 - @Veiksmas: list_two
2 - @PirmasVeiksmas
2 - @AntrasVeiksmas
2 - @Veiksmas: list_three
3 - @PirmasVeiksmas
3 - @AntrasVeiksmas
3 - @TreciasVeiksmas
3 - @KetvirtasVeiksmas
3 - @PenktasVeiksmas

如您所见,它进入下一个序列并按原样继续,但是一旦第三个序列完成,它应该恢复第二个序列并完成第一个序列。但是一旦遇到递归中的第一个死胡同,它就会停止。

EDIT2:我现在拥有的 Codepen 示例以及正在发生的事情的可视化表示:Codepen link

输出应该是:

fa1
second
sa1
third
ta1
ta2
ta3
sa3
fa3

【问题讨论】:

  • 那个php代码是异步的吗?
  • @dandavis 不,这只是一个例子,我只是不明白为什么当它到达第一个死胡同时,承诺链会停止并且必须返回一步(递归)才能继续前一个。
  • 请始终引用您找到代码的位置 - 注明作者,并在此处放置链接!顺便说一句,here's the original(也没有错误)
  • @Bergi 用于单个循环,但是当它归结为递归链接时,它不起作用。据我所知,似乎第一个最深的一端在达到“崩溃”时会回到开始完成承诺链,因此停止任何先前的循环。
  • @IntoDEV:问题是它不会倒塌,你的函数返回的承诺永远不会得到解决。在这里使用 Promise 构造函数是完全错误的。这就是为什么我希望你链接该代码的源代码,以便我可以抨击它的作者。

标签: javascript loops recursion promise chaining


【解决方案1】:

可以使用.reduce() 而不是.map() 来按顺序运行一堆动作。

这是一个例子:

// Helper function that creates a Promise that resolves after a second
const delay = (value) => new Promise(resolve => setTimeout(() => resolve(value), 1000));

const arr = [1, 2, 3, 4, 5];

// concurrent resolution with `.map()` and `Promise.all()`
Promise.all(arr.map(delay))
  .then(console.log.bind(console)); // [1, 2, 3, 4, 5] after a second.

// sequential resolution with `.reduce()`

arr.reduce((promise, current) => 
             promise
               .then(() => delay(current))
               .then(console.log.bind(console)), 
           Promise.resolve());
// second wait, 1, second wait, 2...

如果我正确理解了您的要求,那么您并不完全需要 Promise 递归,这只是您发现按顺序运行 Promises 的方式。 .reduce() 可以更简单地帮助您。

还原过程将[1,2,3,4,5]变成:

Promise.resolve()
  .then(() => delay(1))
  .then(console.log.bind(console))
  .then(() => delay(2))
  .then(console.log.bind(console))
  .then(() => delay(3))
  .then(console.log.bind(console))
  .then(() => delay(4))
  .then(console.log.bind(console))
  .then(() => delay(5))
  .then(console.log.bind(console))

请注意,如果您想访问所有结果,则需要做更多的工作。但我会把它作为练习留给读者:)

【讨论】:

  • 谢谢,但我已经用另一个 stackoverflow 问题解决了这个问题,原来我在使用 jQuery 2.x 时遇到了问题,因为我移到 3.x 后问题自行解决了。我没有在 Promise 本身中使用 jQuery 来保持它们的独立性,但只是在我的代码中使用 jQuery 就搞砸了一些事情。编辑:如果你有兴趣,这里的帖子link
【解决方案2】:

因此,这可以解决您的 codepen 代码的问题,从而提供您想要的输出。

var sequences = {
  first: ['fa1', 'second', 'fa3'],
  second: ['sa1', 'third', 'sa3'],
  third: ['ta1', 'ta2', 'ta3']
};

var loopThrough = (function(sequence) {
  return sequence.forEach(function(action) {
    return doAction(action);
  });
});

var doAction = (function(action) {
  var promise = new Promise(function(resolve, reject) {
    console.log(action);
    if(action == 'second' || action == 'third') {
      //recurse into sub-sequence
      return loopThrough(sequences[action]);
    } else {
      //do something here
    }
    resolve();
  });
  return promise;
});

loopThrough(sequences.first);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-05
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 2013-12-14
    • 2023-01-27
    • 2014-02-04
    • 1970-01-01
    相关资源
    最近更新 更多