Git Product home page Git Product logo

promises-perl's Introduction

Promises for Perl

CPAN version

This module is an implementation of the "Promise/A+" pattern for asynchronous programming. Promises are meant to be a way to better deal with the resulting callback spaghetti that can often result in asynchronous programs.

SYNOPSIS

use AnyEvent::HTTP;
use JSON::XS qw[ decode_json ];
use Promises qw[ collect deferred ];

sub fetch_it {
    my ($uri) = @_;
    my $d = deferred;
    http_get $uri => sub {
        my ($body, $headers) = @_;
        $headers->{Status} == 200
            ? $d->resolve( decode_json( $body ) )
            : $d->reject( $body )
    };
    $d->promise;
}

my $cv = AnyEvent->condvar;

collect(
    fetch_it('http://rest.api.example.com/-/product/12345'),
    fetch_it('http://rest.api.example.com/-/product/suggestions?for_sku=12345'),
    fetch_it('http://rest.api.example.com/-/product/reviews?for_sku=12345'),
)->then(
    sub {
        my ($product, $suggestions, $reviews) = @_;
        $cv->send({
            product     => $product,
            suggestions => $suggestions,
            reviews     => $reviews,
        })
    },
    sub { $cv->croak( 'ERROR' ) }
);

my $all_product_info = $cv->recv;

INSTALLATION

To install this module from its CPAN tarball, type the following:

perl Makefile.PL make make test make install

If you cloned the github repo, the branch releases has the same code than the one living in CPAN, so the same Makefile dance will work. The master branch, however, needs to be built using Dist::Zilla:

dzil install

Be warned that the Dist::Zilla configuration is fine-tuned to my needs, so the dependency list to get it running is ludicrously huge. If you want a quick and dirty install, you can also do:

git checkout releases -- Makefile.PL
perl Makefile.PL
make test
make install

DEPENDENCIES

This module requires these other modules and libraries:

Test::More

This module optionally requires these other modules and libraries in order to support some specific features.

AnyEvent
Mojo::IOLoop
EV
IO::Async

SEE ALSO

COPYRIGHT AND LICENCE

Copyright (C) 2012-2014 Infinity Interactive, Inc.

http://www.iinteractive.com

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

promises-perl's People

Contributors

andykog avatar clintongormley avatar dsteinbrunner avatar ehuelsmann avatar fgasper avatar garu avatar hatorikibble avatar lejeunerenard avatar manwar avatar perlover avatar pmorch avatar rafl avatar rjbs avatar ruz avatar stevan avatar stuckdownawell avatar wangvisual avatar yanick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

promises-perl's Issues

Provide event-loop specific plugins

Hiya @stevan

I'm very much liking Promises, but have run into an issue with deep recursion. You do warn about it:

However, the one important difference that should be noted is that "Promise/A+" strongly suggests that the callbacks given to then should be run asynchronously (meaning in the next turn of the event loop). We do not do this because doing so would bind us to a given event loop implementation, which we very much want to avoid.

...but I didn't quite comprehend how important this issue was until too late.

For a lot of use cases, this limitation is not important. The stack size doesn't get that big before a return which clears this all up. However, I have a couple of use cases where the size of the stack becomes a major problem.

This could be resolved by providing event-loop specific implementations, eg for AnyEvent all you'd need is something like:

package Promises::Deferred::AE;

use AE;
our @ISA = 'Promises::Deferred';

sub _notify {
    my ($self, $callbacks, $result) = @_;
    AE::postpone { $_->( @$result ) } foreach @$callbacks;
    $self->{'resolved'} = [];
    $self->{'rejected'} = [];
}

With an AE version and a Mojo version I think you'd cover most Perl async applications(?). Would you be willing to consider something like this?

Free reject and resolve CBs on resolve/reject

Promises v0.5 will clear resolve callbacks when a promise is resolved, or rejected callbacks when a promise is rejected, but leaves callback references alive in the other group (ie rejected or resolved).

All callbacks should be cleared up once resolution/rejection is complete.

Release of 0.05

Hiya @stevan

I was about to submit a patch for the memory cycle, but I see you've already fixed it. w00t.

Any idea when you plan on releasing this?

ta

Clint

(in cleanup) Can't use an undefined value as an ARRAY reference at ...Promises.pm line 50.

This code is found in Promises.pms _set_warn_on_unhandled_reject:

( ' at ', join ' line ', @{$self->{_caller}} ) x !! $self->{_caller}

But even if $self->{_caller} is undef, @{$self->{_caller}} is still evaluated.

To reproduce:

#!/usr/bin/perl -w
use strict;
use Promises;
my $p = Promises::rejected();

# Simulate a late loaded class using warn_on_unhandled_reject
Promises->import('warn_on_unhandled_reject' => [1]);

which gives the error:

(in cleanup) Can't use an undefined value as an ARRAY reference at ...Promises.pm line 50.

Would a PR creating `die_on_unhandled_reject` be open for consideration?

We have experienced a couple of times that exceptions went unhandled and unnoticed because they were turned into a promise rejection that was never handled.

Looking at Promises.pm, I discovered warn_on_unhandled_reject that is undocumented at the moment. There is a test for it though.

We would like to go a step further and not warn but die on unhandled rejections. It looks quite easy to refactor the current _set_warn_on_unhandled_reject to handle both warn_on_unhandled_reject and a new die_on_unhandled_reject.

Would you be open to a PR for that?

I briefly considered subclassing the Promises classes but it doesn't look feasible because of the way the different Promises::* classes interact. But if you can suggest away for us to achieve die_on_unhandled_reject without modifying the Promises code that would also be great!
(Edit: Appart from the obvious but kludgy $SIG{__WARN__} handler that dies if $_[0] =~ /Promise's rejection .* was not handled/)

Reference to Future.pm in docs?

It'd be useful to have some mention of Future.pm, and maybe AnyEvent's condvars as well, perhaps in the SEE ALSO section. Since they're covering similar ground, a link and possibly a few comments about how Promises.pm compares to them in intent and functionality could be helpful to new users.

Also, is there any plan to include compatibility with Future.pm? Most of the IO::Async ecosystem is based on that (see Net::Async::* for example), along with a few other modules (such as Ryu).

(corresponding RT added for Future.pm here: https://rt.cpan.org/Ticket/Display.html?id=122847 )

Reject cbs which return a value should call resolved handlers

Hiya

It appears that currently Promises are not compliant with http://promises-aplus.github.io/promises-spec/#point-49

Specifically:

promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).

In other words, the reject handler should be able to handle the error (or rethrow it), so this code:

use Promises qw(deferred);
my $d = deferred;
$d->promise
  ->then( sub { say "resolve" }, sub { say "reject" })
  ->then( sub { say "resolve" }, sub { say "reject" });

$d->reject('foo');

should print out:

reject
resolve

when actually it prints out:

reject
reject

The author of AnyEvent::Promises points out this same issue: https://metacpan.org/pod/AnyEvent::Promises#SEE-ALSO

When working with Promises as they are, I found the inability to handle errors and continue down the resolve chain to be an issue, but I assumed that was just how promises worked.

I think this should be changed, but of course it breaks bwc in quite a big way. What do you think? How to handle bwc?

README.md references nonexistent Makefile.PL

Tried building from a fresh git checkout to look more closely at #88 , but the Makefile.PL mentioned in README.md is not present. That might be me confusing user documentation with developer documentation, but maybe a note for what explorers & potential contributors need to do?

t/090-timeout.t fails one test against perl-5.31.10

Today I had occasion to test this distribution against perl-5.31.10 as part of CPAN-River-3000 testing. I observed a failure in t/090-timeout.t, which I was able to reproduce repeatedly:

$ thisprove -vb t/090-timeout.t
t/090-timeout.t .. 
# Subtest: AnyEvent
    1..0 # SKIP Can't locate AnyEvent.pm in @INC (you may need to install the AnyEvent module) (@INC contains: t/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/arch /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10 /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10) at /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib/Promises/Deferred/AnyEvent.pm line 8.
ok 1 # skip Can't locate AnyEvent.pm in @INC (you may need to install the AnyEvent module) (@INC contains: t/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/arch /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10 /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10) at /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib/Promises/Deferred/AnyEvent.pm line 8.
# Subtest: IO::Async
    1..6
    ok 1
    ok 2
    ok 3 - timed out
    ok 4 - p1 still in progress
    ok 5 - p3 resolved
    ok 6 - p4 resolved
ok 2 - IO::Async
# Subtest: AE
    1..0 # SKIP Can't locate AE.pm in @INC (you may need to install the AE module) (@INC contains: t/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/arch /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10 /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10) at /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib/Promises/Deferred/AE.pm line 8.
ok 3 # skip Can't locate AE.pm in @INC (you may need to install the AE module) (@INC contains: t/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/arch /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/site_perl/5.31.10 /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10/amd64-freebsd-thread-multi /home/jkeenan/var/tad/testing/perl-5.31.10/lib/5.31.10) at /usr/home/jkeenan/var/tad/testing/perl-5.31.10/.cpanm/work/1584785680.74982/Promises-1.04/blib/lib/Promises/Deferred/AE.pm line 8.
# Subtest: Mojo
    1..6
    ok 1
    ok 2
    ok 3 - timed out
    ok 4 - p1 still in progress
    ok 5 - p3 resolved
    ok 6 - p4 resolved
ok 4 - Mojo
# Subtest: EV
    1..6
    ok 1
    ok 2
    ok 3 - timed out
    ok 4 - p1 still in progress
    ok 5 - p3 resolved
    # Looks like you planned 6 tests but ran 5.
not ok 5 - EV
1..5

#   Failed test 'EV'
#   at t/090-timeout.t line 13.
# Looks like you failed 1 test of 5.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/5 subtests 
	(less 2 skipped subtests: 2 okay)

Test Summary Report
-------------------
t/090-timeout.t (Wstat: 256 Tests: 5 Failed: 1)
  Failed test:  5
  Non-zero exit status: 1
Files=1, Tests=5,  4 wallclock secs ( 0.05 usr  0.02 sys +  0.26 cusr  0.14 csys =  0.47 CPU)
Result: FAIL

Note: The AnyEvent module currently fails to install against blead, so the fact that certain tests are SKIPped is not the problem here. The problem is that subtest EV fails to run completely.

Not yet further investigated.

$ uname -mrs
FreeBSD 12.0-RELEASE amd64
$ thisperl -v | head -2 | tail -1
This is perl 5, version 31, subversion 10 (v5.31.10) built for amd64-freebsd-thread-multi

Thank you very much.
Jim Keenan

Easy subclassing of any Deferred handler

As per #80 I am subclassing ::Deferred. However I typically want to subclass a subclass of that depending on the IO loop in order to enable timeouts etc. What is the easiest way of doing this - the only way I could think of at the moment was to declare the subclass with

our @ISA = ( $Promises::Backend );

which seems really hacky to me and will only work if the backend is defined prior to using the subclass...

[RFC] shortcut for chained `then`s

So in my code I have a bunch of chained thens:

    $rpc->api->vim_get_current_buffer
        ->then(sub{ $buffer_id = ord $_[0]->data })
        ->then(sub{ $rpc->api->vim_input( "1GdG" ) })
        ->then(sub{ $rpc->api->buffer_insert( $buffer_id, 0, [ 
            map { $_->{description} } $tw->export_tasks
        ] ); });

which I already can de-noisify a wee bit via:

    reduce { $a->then($b) } 
        $rpc->api->vim_get_current_buffer,
        sub{ $buffer_id = ord $_[0]->data },
        sub{ $rpc->api->vim_input( "1GdG" ) },
        sub{ $rpc->api->buffer_insert( $buffer_id, 0, [ 
            map { $_->{description} } $tw->export_tasks
        ] ); };

I'm wondering, though, if it would be worthwhile to have a special case
of then where

$p->then( \@then, $else )

gets expanded to

$p->then( $then[0] )->then( $then[1] )->..->catch($else)

to that the above code would become

    $rpc->api->vim_get_current_buffer->then([
        sub{ $buffer_id = ord $_[0]->data },
        sub{ $rpc->api->vim_input( "1GdG" ) },
        sub{ $rpc->api->buffer_insert( $buffer_id, 0, [ 
            map { $_->{description} } $tw->export_tasks
        ] ); }
    ]);

Alternatively, if the different behaviors of then feels wrong, perhaps a chain method that does

    $p->chain( @then );
    # equivalent to
    reduce { $a->then($b) } $p, @then;

?

If any of those feel appealing to you, I'd be delighted to submit a patch.

Adding a resolved promise to collect causes an exception

A simple test case:

use Promises qw( collect deferred );

collect( deferred->resolve->promise );

throws:

Cannot resolve. Already  resolved at /home/greg/perl5/perlbrew/perls/perl-5.16.2/lib/site_perl/5.16.3/Promises/Deferred.pm line 49.

It appears that the collect promise is being resolved both in the loop and at the end of the method:

Cannot resolve. Already  resolved at /home/greg/perl5/perlbrew/perls/perl-5.16.2/lib/site_perl/5.16.3/Promises/Deferred.pm line 49.
    Promises::Deferred::resolve('Promises::Deferred=HASH(0x23a6848)', 'ARRAY(0x23a6a10)') called at /home/greg/perl5/perlbrew/perls/perl-5.16.2/lib/site_perl/5.16.3/Promises.pm line 60
    Promises::collect('Promises::Promise=HASH(0x22b5570)') called at /home/greg/test.pl line 3

I assume this is not the intended behavior.

The new pipe based implementation will leave one EV handler

In the latest version:
my $socket_io;
$socket_io = EV::io($socket_recv, EV::READ, &_do_callbacks);

This $socket_io is an EV handler, and it will prevent EV::loop from exiting.

Unfortunately my program need all EV handler be undefined or mark the handler keepalive(0).

So please either make it keepalive(0) or provide an API like cleanup().

Thanks.

Promises-1.02 install fails on Ubuntu 18.04 plenv

Perhaps similar to #87

I've tried and failed to instal AnyEvent-HTTP-2.24 then Promises-1.02 into two different fresh perl installations (using the plenv binary manager: https://github.com/tokuhirom/plenv).

Attached:

  • the full console log bug-report-full.txt

  • the build logs from perl 5.30.1 promises-build-5-30-1.log
    and the SAME result from perl 5.14.4!) promises-build-5-14-4.log

    Linux Ubuntu 18.04 / x86_64
    $ uname -a
    Linux rowan 4.15.0-47-generic #50-Ubuntu SMP Wed Mar 13 10:44:52 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

    $ env | egrep '^(PATH|PERL|PLENV)'
    PATH=/home/ddd/.plenv/shims:/home/ddd/.plenv/bin:/home/ddd/bin/linux-x86_64:/home/ddd/bin:/home/ddd/ds/bin:/home/ddd/work/home/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/games:/snap/bin:/bin
    PLENV_SHELL=bash
    PLENV_VERSION=5.30.1

    $ type -a perl
    perl is /home/ddd/.plenv/shims/perl
    perl is /usr/bin/perl

    $ perl --version
    This is perl 5, version 30, subversion 1 (v5.30.1) built for x86_64-linux
    ...
    <<attached full output from perl -V>>

    $ env | egrep '^(PATH|PERL|PLENV)'
    PATH=/home/ddd/.plenv/shims:/home/ddd/.plenv/bin:/home/ddd/bin/linux-x86_64:/home/ddd/bin:/home/ddd/ds/bin:/home/ddd/work/home/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/games:/snap/bin:/bin
    PLENV_SHELL=bash
    PLENV_VERSION=5.30.1

    $ type -a perl
    perl is /home/ddd/.plenv/shims/perl
    perl is /usr/bin/perl

    $ plenv install 5.30.1
    $ plenv local 5.30.1
    $ plenv shell 5.30.1
    $ plenv versions
    system
    5.14.4

    • 5.30.1 (set by PLENV_VERSION environment variable)

    $ type -a perl
    perl is /home/ddd/.plenv/shims/perl
    perl is /usr/bin/perl

    $ plenv install-cpanm
    $ type -a cpanm
    cpanm is /home/ddd/.plenv/shims/cpanm
    $ plenv which cpanm
    /home/ddd/.plenv/versions/5.30.1/bin/cpanm

    $ cpanm AnyEvent::HTTP
    --> Working on AnyEvent::HTTP
    ...
    4 distributions installed

    $ cpanm Promises
    --> Working on Promises
    ...
    Test Summary Report

    t/031-deferred-AE.t (Wstat: 256 Tests: 2 Failed: 1)
    Failed test: 2
    Non-zero exit status: 1
    t/032-deferred-AnyEvent.t (Wstat: 256 Tests: 2 Failed: 1)
    Failed test: 2
    Non-zero exit status: 1
    Files=36, Tests=155, 10 wallclock secs ( 0.14 usr 0.08 sys + 4.07 cusr 0.54 csys = 4.83 CPU)
    Result: FAIL
    Failed 2/36 test programs. 2/155 subtests failed.
    Makefile:947: recipe for target 'test_dynamic' failed
    make: *** [test_dynamic] Error 255
    -> FAIL Installing Promises failed. See /home/ddd/.cpanm/work/1577367375.6160/build.log for details. Retry with --force to force install it.

CPAN installation fails on macOS (Mojave)

t/031-deferred-AE.t .............. 1/?
#   Failed test '... run asynchronously'
#   at t/031-deferred-AE.t line 26.
#          got: '0'
#     expected: '1'
# Looks like you failed 1 test of 2.
t/031-deferred-AE.t .............. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/2 subtests
t/031-deferred-io-async.t ........ ok
t/032-deferred-AnyEvent.t ........ 1/?
#   Failed test '... run asynchronously'
#   at t/032-deferred-AnyEvent.t line 26.
#          got: '0'
#     expected: '1'
# Looks like you failed 1 test of 2.

Should callbacks be eval'ed

The problem in #14 got me thinking about how callbacks are being called. Throwing exceptions in an event loop is problematic -- quite likely it'll end up with some condition never being met.

I'm not that familiar with the Promises spec, but it seems to say (I think) that if any callback throws an exception, that should be propagated to any reject handlers. Currently the code allows callbacks to call fatal exceptions, which would prevent that from happening.

have a look at this code: https://github.com/then/promise/blob/master/core.js#L25-L40

It wraps the callbacks in a try block, so will never throw exceptions directly. What do you think? I'll put together a PR that I think implements this correctly.

Rejections are not propagated

I've been stealing some of the internal design of Promises for Mojolicious, and noticed that rejections are not propagated through the promise chain. It looks like this line should be $d->$method(@results); instead of $d->resolve(@results);.

You can test this by chaining multiple ->catch(sub {...}) calls. Propagating rejections is a requirement of Promises/A+.

collect() eats 100% cpu when called without arguments

While I do understand this isn't the intended use-case, this code triggered the above condition for me:

    collect(map { $_->validate() } @resources)
    ->then(sub { call_after_all_finished(); });

Where each validate() method returns a promise, but @resources was empty. I'm not interested in the values to which the promises resolve; basically, they're only used to wait for all actions to be completed before going to the final step.

Mojo::UserAgent example for Promises::Cookbook::TIMTOWTDI

https://rt.cpan.org/Ticket/Display.html?id=96790

#!/usr/bin/perl use Mojo::Base -strict; use Mojo::UserAgent; my $titles; my $ua = Mojo::UserAgent->new; Mojo::IOLoop->delay( sub { my $delay = shift; $ua->get('http://google.com/', $delay->begin); $ua->get('http://yahoo.com/', $delay->begin); $ua->get('http://perlmonks.org/', $delay->begin); }, sub { my ($delay, $tx1, $tx2, $tx3) = @_; $titles = { google => $tx1->res->dom->at('title')->text, yahoo => $tx2->res->dom->at('title')->text, perlmonks => $tx3->res->dom->at('title')->text, }; }, )->catch( sub { my ($delay, $err) = @_; warn "failed to download or parse title\n"; } )->wait; say Mojo::Util::dumper($titles);

Mention Future.pm in SEE ALSO

Subset of #63

It'd be useful to have some mention of Future.pm, and maybe AnyEvent's condvars as well, perhaps in the SEE ALSO section. Since they're covering similar ground, a link and possibly a few comments about how Promises.pm compares to them in intent and functionality could be helpful to new users.

Compatibility with Future.pm?

Subset of #63

plan to include compatibility with Future.pm? Most of the IO::Async ecosystem is based on that (see Net::Async::* for example), along with a few other modules (such as Ryu).

That should be helped with the creation of a Promise role that is coming with #44.

Flattening the return stack

In my quest to make Promises recursive, I've come across another issue: because promises are chained, the return stack can become enormous. JS seems to use tail calls to flatten this out (I think) but of course this doesn't work in Perl.

For a use case imagine processing each record in a database one after another (not all at the same time), then returning when all done (or when a failure occurs)

What I needed was this:

$loop = sub {
   if ($done) { return $deferred->resolve;
   something()->then(...)->then(...)
   ->then(
       sub { AE::postpone { $loop->() }; return }
       sub { $deferred->reject(@_)
   )
};
$loop->();

But I want to write that without knowing ahead of time which event loop is being used. I tried to make it work with goto $loop but that last then() is still waiting for a return value.

The solution I've come up with is then_discard() which works just like then() but doesn't return a promise.

$loop = sub {
   if ($done) { return $deferred->resolve;
   something()->then(...)->then(...)
   ->then_discard(
       sub { AE::postpone { $loop->() }; return }
       sub { $deferred->reject(@_)
   )
};
$loop->();

So the callback is scheduled for execution in the event loop and then it returns, unwinding the return stack.

See the PR for details.

Does the name then_discard() make sense to you? It is so called because the return values are discarded instead of being passed to the next promise.

Difference between exception & reject

Now the exceptions happen in 'then' will be treat as reject and the reject handler will be called later, eg:

$promise->then( sub {
RUN_TIME_ERROR_HERE;
})->then(undef, sub {
FATAL @
;
});

The FATAL will be called with something like:
Can't use string ("1455362825.71571") as an ARRAY ref while "strict refs" in use at /depot/perl-5.22.0/lib/5.22.0/x86_64-linux/Time/HiRes.pm line 74

But IMHO, exception is different with reject as later is the one that author intend to do so. Also in my application I would like to print the whole call stack when error happens, but now the error stack is like:

[STACK]
Package => main, File => a.pl, Line => 602, Sub => CommonUtil::FATAL
Package => Promises::Deferred, File => .../lib/perl5/Promises/Deferred.pm, Line => 133, Sub => main::ANON
Package => Promises::Deferred, File => .../lib/perl5/Promises/Deferred.pm, Line => 136, Sub => (eval)
Package => Promises::Deferred::EV, File =>.../lib/perl5/Promises/Deferred/EV.pm, Line => 19, Sub => Promises::Deferred::ANON
Package => main, File => a.pl, Line => 934, Sub => Promises::Deferred::EV::ANON
Package => main, File => a.pl, Line => 934, Sub => (eval)
Package => main, File => a.pl, Line => 1667, Sub => main::main

But what I want is to have the FATAL to show the line for _RUN_TIME_ERROR_HERE, so either

  1. Please provide a function 'then_no_eval' or what ever.
  2. Please help to provide the stack trace when eval in _wrap failed.
  3. The way that you think should be correct.

Sorry for my English :-)

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.