使用Bluebird Promises的While循环

17

我正在尝试使用Promise实现while循环。

这里概述的方法似乎可行。http://blog.victorquinn.com/javascript-promise-while-loop它使用了以下函数

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
    var resolver = Promise.defer();

    var loop = function() {
        if (!condition()) return resolver.resolve();
        return Promise.cast(action())
            .then(loop)
            .catch(resolver.reject);
    };

    process.nextTick(loop);

    return resolver.promise;
};

看起来这里使用了反模式和过时的方法,例如cast和defer。

有没有人知道更好或更现代的方法来实现这个?

谢谢


你能用语言解释一下你真正想要实现什么吗?请记住,在Javascript中,忙等待循环是一件可怕的事情。使用某种事件处理程序而不是在紧密循环中重复调用某些东西更有意义。action()函数具体做什么呢?也许可以展示一个如何使用它的例子? - jfriend00
2个回答

20

cast可以翻译为resolvedefer应该确实不应该使用

您只需在初始的Promise.resolve(undefined)上链接和嵌套then调用,即可创建循环。

function promiseWhile(predicate, action, value) {
    return Promise.resolve(value).then(predicate).then(function(condition) {
        if (condition)
            return promiseWhile(predicate, action, action());
    });
}

在这里,predicateaction都可以返回承诺。如需类似的实现,请参阅正确编写承诺循环的方法。更接近您原始函数的实现如下:
function promiseWhile(predicate, action) {
    function loop() {
        if (!predicate()) return;
        return Promise.resolve(action()).then(loop);
    }
    return Promise.resolve().then(loop);
}

你可以更改 loop 函数以接受一个值,然后在谓词为 false 时解析它,以获取 action 函数返回的最后一个值。 - Sami
1
@JakeWilson 这是用于检查的谓词的初始值。当测试函数不需要任何参数时,可以省略它。 - Bergi
谢谢@Bergi。你的示例评论被删除了吗?也许你可以把示例添加到答案中? - Jake Wilson
你的代码明显不能工作。你的示例有问题,原始代码也有问题(conditionpredicate??)。如果你能在 CodePen 或其他地方发布一个可工作的示例,那就更好了。 - Jake Wilson
@JakeWilson predicate 是一个函数,condition 是它返回的布尔值。 - Bergi
显示剩余5条评论

3

我更喜欢这种实现方式,因为它更容易模拟 break 和 continue:

var Continue = {}; // empty object serves as unique value
var again = _ => Continue;

var repeat = fn => Promise.try(fn, again)
  .then(val => val === Continue && repeat(fn) || val);

示例1:当源或目标指示出错时停止

repeat(again => 
    source.read()
    .then(data => destination.write(data))
    .then(again)

例子2:如果给定90%的概率结果为0,随机停止。
var blah = repeat(again =>
    Promise.delay(1000)
    .then(_ => console.log("Hello"))
    .then(_ => flipCoin(0.9) && again() || "blah"));

示例3:带有返回总和的条件循环:

repeat(again => {
  if (sum < 100) 
    return fetchValue()
      .then(val => sum += val)
      .then(again));
  else return sum;
})

1
我可能会使用“Symbol”来表示唯一值,但除此之外看起来很不错 :) - Benjamin Gruenbaum
god thinking benji - Alexander Mills

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接