Search code examples
perlpromisemojoliciousmojo-useragent

How to assign promise returned from get_p to a variable?


I tried to return a promise from a subroutine which contained some data obtained from a HTTP request to a web server. But I couldn't call then on the result. Having narrowed it down, it doesn't seem possible to assign the promise returned from get_p to a variable and then use it as a promise.

Here's an example. I would have thought that the two requests are exactly the same, but only the second one runs the code in the then block.

Can someone please explain what the difference is, and how I should return a promise from a subroutine if I want to chain more then methods outside the sub?

#!/usr/bin/perl -w

use strict;
use warnings;
use utf8;
use 5.024;

use Data::Dumper;
use Mojo::IOLoop;
use Mojo::UserAgent;

my $promise = Mojo::UserAgent->new->get_p('http://example.com');
$promise->then(sub {
    my $tx = shift;
    warn 'Using variable';
    warn $tx->result->body;
})->wait;

Mojo::UserAgent->new->get_p('http://example.com')
->then(sub {
    my $tx = shift;
    warn 'Not using variable';
    warn $tx->result->body;
})->wait;

Solution

  • All active connections created by a UA object are closed when the UA object is destroyed. The promise doesn't reference the UA object, so you must ensure the UA object doesn't get destroyed.

    #!/usr/bin/perl -w
    
    use strict;
    use warnings;
    use utf8;
    use 5.024;
    
    use Mojo::IOLoop;
    use Mojo::UserAgent;
    
    my $ua = Mojo::UserAgent->new;
    
    my $promise = $ua->get_p('http://example.com');
    $promise->then(sub {
        my $tx = shift;
        warn 'Using variable';
        warn $tx->result->body;
    })->wait;
    
    $ua->get_p('http://example.com')
    ->then(sub {
        my $tx = shift;
        warn 'Not using variable';
        warn $tx->result->body;
    })->wait;
    

    Since Perl uses reference counting for garbage collection, one couldn't be faulted for believing that objects are destroyed as soon as nothing references them. In reality, an object can survive until the end of the statement in which it became unreferenced. (This is a side-effect of the mechanism used to compensate for the stack's references not being counted.)

    Your test worked when you only used a single statement because the UA object survived until the end of the statement, and thus after wait returned.