So I've uploaded Mojo::Promise::Role::Repeat to CPAN.
This adds a single method to Mojo::Promise
$done_p = $promise->repeat(sub{...})
which is essentially equivalent to
$done_p = $promise->then(sub{...})->then(sub{...})->then(sub{...})->then(sub{...}) #... forever
The promise returned represents the end of the chain off at infinity, meaning
- if any instance of the handler sub{...} dies or returns a rejected promise
$done_p is rejected with the same @reason(s). - if any instance of sub {...} calls $_->(@values) -- $_ is bound to an escape function that does not return --
$done_p is resolved with @values (and execution of everything else in the loop is abandoned).
and these are the only ways out of the loop. If a handler run returns normally or returns a resolved promise, the return values become the arguments for the next iteration (as one would expect for consecutive then()s).
The function bound to $_ also works from inside of nested handlers/loops (though you'll want to stash it in a lexical if you're going to do that since $_ will probably be set to something different by the time the nested handler runs). Meaning you can do stuff like this
$ua->get_p(...)->repeat(sub{
my $break = $_;
...
$ua->get_p(...)->repeat(sub {
...
$ua->get_p(...)->then(sub {
...
$break->('bye') if (condition);
...
}
...
}
...
})
Anyway it's up. Enjoy.