AnyEvent-Promise
view release on metacpan or search on metacpan
lib/AnyEvent/Promise.pm view on Meta::CPAN
=head1 SYNOPSIS
Avoid the evented pyramid of doom!
use AnyEvent::Promise;
use AnyEvent::Redis;
my $redis = AnyEvent::Redis->new();
my $p = promise(sub {
$redis->get('test');
})->then(sub {
$redis->set('test', shift);
})->then(sub {
$redis->get('test');
})->then(sub {
say shift;
})->catch(sub {
say 'I failed!';
say @_;
})->fulfill;
=head1 DESCRIPTION
L<AnyEvent::Promise> allows evented interfaces to be chained, taking away some
of the redundancy of layering L<AnyEvent> condition variable callbacks.
A promise is created using L<AnyEvent::Promise::new|/new> or the exported
L</promise> helper function. These will both return a promise instance and add
the callback function as the start of the promise chain. Each call to L</then>
on the promise instance will add another subroutine which returns a condition
variable to the chain.
The promise callback chain won't start until L</condvar> or L</fulfill> is
called on the instance. Calling L</condvar> or L</cv> will start the callback
chain and return the promise guarding condvar, which is fulfilled after the last
callback on the chain returns. Similarily, L</fulfill> will start the chain, but
will block until the guarding condvar is fulfilled.
Errors in the callbacks can be caught by setting an exception handler via the
L</catch> method on the promise instance. This method will catch exceptions
raised from L<AnyEvent> objects and exceptions raised in blocks provided to
L</then>. If an error is encountered in the chain, an exception will be thrown
and the rest of the chain will be skipped, jumping straight to the catch
callback.
=head1 EXPORT
=head2 promise($cb)
Start promise chain with callback C<$cb>. This function is a shortcut to
L<AnyEvent::Promise::new|/new>, and returns a promise object with the callback
attached.
=cut
sub promise { AnyEvent::Promise->new(@_) }
sub import {
no strict 'refs'; ## no critic (ProhibitNoStrict)
*{caller() . '::promise'} = \&promise;
}
=head1 METHODS
=head2 new($cb)
Create an instance of a promise, start the chain off with callback C<$cb>. See
L</then> for information on passing in a callback and condvar.
=cut
sub new {
my ($class, $cb) = @_;
my $self = bless {
guard => undef,
initial => undef,
fulfill => undef,
reject => undef,
rejected => 0
}, $class;
$self->{guard} = AnyEvent->condvar;
$self->{initial} = AnyEvent->condvar;
my $reject = AnyEvent->condvar;
$reject->cb(sub {
carp shift->recv;
$self->{guard}->send;
});
$self->{reject} = $reject;
$self->then($cb);
return $self;
}
=head2 then($cb)
Add callback C<$cb> on to the promise chain.
This callback will receive the return of the previous callback -- i.e. the
callback will receive the value sent by the previous condvar directly. In order
to continue the promise chain, the callback should return a condvar.
Instead of:
my $cv = $redis->get('test');
$cv->cb(sub {
my $ret = shift->recv;
my $cv2 = $redis->set('test', $ret);
$cv2->cb(sub {
my $cv3 = $redis->get('test');
$cv3->cb(sub {
my $ret3 = shift->recv;
printf("Got a value: %s\n", $ret3);
});
});
});
$cv->recv;
( run in 5.090 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )