The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Promises6 - brand new module Promises6

VERSION

version 0.003

SYNOPSIS

  use Evo::Base -strict;
  use Promises6 ':all';
  use Mojo::IOLoop;
  use Mojo::UserAgent;

  $| = 1;
  Mojo::IOLoop->recurring(0.02, sub { print '.' });
  my $ua = Mojo::UserAgent->new;

  sub promise_me($n) {
    my $deferred = deferred;
    my $i        = 0;
    Mojo::IOLoop->recurring(0.2,
      sub { $deferred->notify($i); $deferred->resolve($i) if ++$i > $n });
    $deferred->promise;
  }

  # dsl style
  promise {
    my ($resolve, $reject, $progress) = @_;
    $resolve->(promise_me(5));

    then sub($v) { say "fulfilled: $v" };

    when_progress { say "progress $_[0]" };

    # then sub{}, undef, undef;
    when_ok { Mojo::IOLoop->stop };
    Mojo::IOLoop->start;
  };


  # ES6 style
  sub get_promise($url) {
    promise {
      my $resolve = shift;
      $ua->get($url => sub { $resolve->($_[1]) })
    }
  }

  # get all, dsl
  promise {
    my $all = all(
      goole   => get_promise('http://google.com'),
      yandex  => get_promise('http://yandex.ru'),
      alexbyk => get_promise('http://alexbyk.com')
    );
    shift->($all);

    when_ok {
      my %hash = $_[0]->@*;
      foreach my $k (keys %hash) {
        say "$k: ", $hash{$k}->res->dom->at('title');
      }
    };

    when_rejected { warn $_[0] };

    then sub { Mojo::IOLoop->stop };


  };
  Mojo::IOLoop->start;

  # who is faster
  race(
    get_promise('http://google.com'),
    get_promise('http://yandex.ru'),
    get_promise('http://alexbyk.com')
    )

    ->then(sub { say "faster: " . $_[0]->req->url }, sub { warn $_[0] })
    ->then(sub { Mojo::IOLoop->stop });

  Mojo::IOroop->start;

DESCRIPTION

Why I started this module? The reason is simple - existing Promises.pm can't pass the basic tests (see examples), so the can't work with thenable objects. And that's the main point of Promises - without this feature it doesn't make sense to use it at all

My implementation used to be 100% Promises/A+ compatible, including optional thenable recursion detector requirement. It's simple and clear.

It provides Deferred, ES6 and DSL syntaxes. Progress notification future just like in JS Q library also implemented.

It doesn't need a special EventLoop, because it implements it's own run out from recursion pattern. So recursion are not a problem for it

Wait for the first public release.

METHODS

promise

Returns a promise in ES6 style. Also supports DSL methods then, when_rejected, when_progress

deferred

Returns a deferred object

resolved, rejected

  my $promise = resolved('Foo');
  my $promise2 = rejected('Reason');

Returns a resolved or rejected promise with a given value/reason

then, when_ok, when_rejected, when_progress

  promise {
    my ($resolve, $reject, $progress) = @_;

    then sub {...}, sub {}, sub {};

    # then undef, undef, sub {};
    when_progress {...};

    # then undef, sub;
    when_rejected {...};

    # then sub {};
    when_ok {...};
  };

DSL methods. Use it inside "promise" to organaze a chain without in nice DSL style

race

Returns a promise that will be immidiately rejected or resolved with the value of first result

all

Returns a promise that resolves when all of the promises in the list argument have resolved. Reject immidiately with the reason of the first rejected promise

  all(foo => promise(), bar => promise2());

You can pass scalar values for convinience to convert a result to the hash.

ATTENTION

Don't use it before the stable 1.0 release. Don't rely on the internal implementation, it's a subject to change. This is an early prototype

IMPLEMENTATION

The basic implementation is simple. I tried to make this module as a replacement for existing Promises so I used the same classes Deferred, Promise etc. But looks like it's better to avoid Deferred syntax, and I'm going to rewrite it.

ES6 syntax is more stable and shouldn't change in the future.

My implementation doesn't need an event loop, because it implements own next_tick. So the recursion isn't a problem for Promises6, and it should work much faster (or use much less memory) than other implementations.

See bench/promises-recursion.pl

working with thenables

This module works with existing Promises, or other thenable object when you start your chain with Promises6. When you start your chain with other module, it should works too, but if that module is Promises A+ compatible. Promises.pm isn't.

next_tick and EventLoops perfomance

Don't try to write EventLoop backend. I've written EV example for you only to show, that right now current implementation do the right thing without event_loop. And even the fastest one works 10-20 times slower than pure perl with even syntax sugar. That's because timer 0,0 isn't the same thing as a next_tick.

In the most cases event loop would be the bottleneck, so don't worry.

perl 5.20.0

this module requires perl 5.20.0 because everybody knows that nice people use the latest release. Promises6 are for nice persons only

PS

Don't use it before 1.0. And sorry for my English.

AUTHOR

alexbyk <alexbyk.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by alexbyk.

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