1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
package Promise::XS::Deferred;
use strict;
use warnings;
=encoding utf-8
=head1 NAME
Promise::XS::Deferred - deferred object
=head1 SYNOPSIS
See L<Promise::XS>.
=head1 DESCRIPTION
This class implements a promise’s “producer” behavior. It is not
to be instantiated directly, but rather via L<Promise::XS>.
=head1 BASIC METHODS
The following are what’s needed to implement normal promise workflows:
=head2 $obj = I<OBJ>->resolve( @ARGUMENTS )
Resolves I<OBJ>’s promise, assigning the given @ARGUMENTS as the value.
Returns I<OBJ>.
B<IMPORTANT:> Behavior here is B<not> defined if anything in @ARGUMENTS is
itself a promise.
=head2 $obj = I<OBJ>->reject( @ARGUMENTS )
Like C<resolve()> but rejects the promise instead.
=head1 ADDITIONAL METHODS
=head2 $yn = I<OBJ>->is_pending()
Returns a boolean that indicates whether the promise is still pending
(as opposed to resolved or rejected).
This shouldn’t normally be necessary but can be useful in debugging.
For compatibility with preexisting promise libraries, C<is_in_progress()>
exists as an alias for this logic.
=head2 $obj = I<OBJ>->clear_unhandled_rejection()
Ordinarily, if a promise’s rejection is “unhandled”, a warning about the
unhandled rejection is produced. Call this after C<reject()> to silence
that warning. (It’s generally better, of course, to handle all errors.)
=cut
#----------------------------------------------------------------------
*is_in_progress = *is_pending;
our $_NOTHING_CR = sub { };
#----------------------------------------------------------------------
# Undocumented, by design:
sub set_deferral_AnyEvent() {
require AnyEvent;
___set_deferral_generic(
AnyEvent->can('postpone') || \&_anyevent_postpone_compat,
undef,
_DEFER_ANYEVENT(),
);
}
sub set_deferral_IOAsync {
my ($loop) = @_;
___set_deferral_generic(
$loop->can('later') || \&_ioasync_later_compat,
$loop,
_DEFER_IOASYNC(),
sub { $loop->stop() },
);
}
sub set_deferral_Mojo() {
require Mojo::IOLoop;
___set_deferral_generic(
Mojo::IOLoop->can('next_tick') || \&_mojo_next_tick_compat,
'Mojo::IOLoop',
_DEFER_MOJO(),
sub { Mojo::IOLoop->stop() },
);
}
#----------------------------------------------------------------------
# Polyfills for old versions of the event loops that didn’t include
# zero-timer convenience functions:
my %ae_timer;
sub _anyevent_postpone_compat {
my $cb = $_[0];
my ($w, $w_str);
$w = AnyEvent->timer( after => 0, cb => sub {
delete $ae_timer{$w_str};
$cb->();
} );
$w_str = "$w";
$ae_timer{$w_str} = $w;
}
sub _ioasync_later_compat {
local ($@, $!);
require IO::Async::Timer;
$_[0]->add( IO::Async::Timer->new(
mode => 'countdown',
delay => 0,
on_expire => $_[1],
)->start() );
}
sub _mojo_next_tick_compat {
Mojo::IOLoop->timer( 0, $_[1] );
}
1;
__END__
sub _ioasync_wait_promise {
my $loop = $_[1];
$_[0]->catch(\&_NOTHING)->finally(sub { $loop->stop() } );
$loop->run();
}
|