manakai / perl-promise

Promise in Perl

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NAME

Promise - Promise for Perl

SYNOPSIS

use Promise;

$p = Promise->new (sub {
  my ($resolve, $reject) = @_;
  some_async_action (sub {
    if ($error) {
      $reject->($error);
    } else {
      $resolve->($result);
    }
  });
});
$p->then (sub {
  my $result = shift;
  ...
}, sub {
  my $error = shift;
  ...
});

DESCRIPTION

The Promise module defines a promise class which exposes methods similar to those of the JavaScript Promise class.

A promise is either to be fulfilled or to be rejected. When the promise is fulfilled with a value, any fulfilled callback registered with the promise is invoked with the value. When the promise is rejected with a value, any rejected callback registered with the promise is invoked with the value. Any number of fulfilled and rejected callbacks can be registered. Callbacks can be registered anytime, before or after fulfilling or rejecting of the promise. Each callback is invoked at most once for the promise.

A promise can be resolved. When a promise is resolved with another promise, the original promise is fulfilled or rejected once the other promise is fulfilled or rejected, with the same value. When a promise is resolved with a non-promise value, the promise is fulfilled with the value.

Note that fulfilling a promise without value is equivalent to fulfilling a promise with the value of undef.

For the purpose of resolution, any Perl object with the then method defined is a promise. That is, promise objects implementing other Perl classes can be used in mixture with these Promise objects.

METHODS

There are following class methods:

$p = Promise->new (CODE)

Create a new promise object. There must be an argument, which must be a code reference. It is expected that the code, when invoked, calls either the first or the second argument to the code synchronously or asynchronously.

To resolve the promise created, the first argument ($_[0]), which is a code reference, must be invoked. If an argument is specified to the code, it is used to resolve the promise. Otherwise, undef is used to resolve the promise.

To reject the promise created, the second argument ($_[1]), which is a code reference, must be invoked. If an argument is specified to the code, it is used to reject the promise. Otherwise, undef is used to reject the promise.

$p = Promise->resolve ($x)

Return a promise which is resolved with the value specified as the argument. If the argument is a promise, that promise is returned as is. Otherwise, a new promise is created.

$p = Promise->reject ($r)

Create and return a new promise which is rejected with the value specified as the argument.

$p = Promise->all ([$p1, $p2, ...])

Create a new promise object, which is to be fulfilled when all of the promises specified in the argument are fulfilled.

The argument must be an array reference (or an object which can be evaluated as if it were an array reference).

The promise created is to be fulfilled when all of the promises are fulfilled, with an array reference which contains the resolved values of the values included in the array in the argument, in same order.

The promise is to be rejected when any of the promises is rejected, with the value of the rejected promise.

$p = Promise->race ([$p1, $p2, ...])

Create a new promise object, which is to be fulfilled when any of the promises specified in the argument are fulfilled.

The argument must be an array reference (or an object which can be evaluated as if it were an array reference).

The promise is to be fulfilled or rejected when any of the promises is fulfilled or rejected, with the value of the fulfilled or rejected promise.

$p = Promise->from_cv ($cv)

Create a promise, which is resolved with the value received by the condvar specified as the argument.

The argument is typically an AnyEvent::CondVar object, though any object compatible with AnyEvent::CondVar API can be used. The argument must be an object with the cb method with a code reference argument, which is to be invoked with an object with recv method. If the recv method returns a value (i.e. $cv->send is invoked), the promise is resolved with the value. If the recv method throws (i.e. $cv->croak is invoked), the promise is rejected with the exception.

A promise has following methods:

$p2 = $p->then ($onfulfilled, $onrejected)

Register callback functions invoked when the promise is fulfilled or rejected. The arguments are the fulfilled and rejected callbacks, in order. The arguments can be omitted (or specify the undef value).

The fulfilled callback is invoked when the promise is fulfilled, with the value of the fulfillment as the argument. The default fulfilled callback just returns the argument.

The rejected callback is invoked when the promise is rejected, with the value of the rejection as the argument. The default rejection callback just throws the argument.

The method returns a new promise. If the fulfilled callback or the rejected callback returns a value, the new promise is resolved with the value. If the fulfilled callback or the rejected callback throws an exception, the new promise is rejected with the exception.

Examples:

Promise->resolve (3)->then (sub { warn shift }); # 3
Promise->reject (4)->then (sub { never }, sub { warn shift }); # 4
...->then (sub { die 5 })
   ->then (undef, sub { $_[0] })
   ->then (sub { warn shift });               # 5
...->then (sub { Promise->reject (6) })
   ->then (undef, sub { warn shift });        # 6
...->then (sub { die 7 })
   ->then (sub { never }, sub { die $_[0] })  # die with 7
...->then (sub { die 8 })
   ->then (sub { 10 })
   ->then (sub { never }, sub { warn $_[0] }) # 8
$p2 = $p->catch ($onrejected)

Register a callback function invoked when the promise is rejected. The argument is the rejected callback. This method has same effect as $p2 = $p->then (undef, $onrejected).

$p2 = $p->finally ($onfinally)

Register a callback function invoked when the promise is fulfilled or rejected. The argument is the callback.

The method returns a new promise. If the callback throws an exception, or the callback returns a promise that is rejected with an exception, the new promise is rejected with the exception. Otherwise, once the return value of the callback is resolved, the new promise is fulfilled with the value of the fulfillment of the original promise, or rejected with the exception of the rejection of the original promise.

The callback can be used for e.g. closing any resource opened by preceding callbacks.

Example:

$database->open->then (sub {
  $database->... # or reject
})->finally (sub {
  return $database->close;
});
$cv = $p->to_cv

Create and return an AnyEvent::CondVar object. When the promise is fulfilled, the condvar receives the result value (i.e. $cv->recv returns the value). When the promise is rejected, the condvar is croaked with the thrown value (i.e. $cv->recv croaks with the value). Apparently this method requires AnyEvent.

$p->manakai_set_handled

Mark the promise "handled", as if the then method were invoked, without creating a new promise or enqueueing handlers, supressing "uncaught rejection" warning. (In the ECMAScript specification terms, this method sets the [[PromiseIsHandled]] internal slot to true.)

$string = $p->debug_info

Return a short character string that might be useful for debugging.

All methods except for from_cv and debug_info act in similar way to methods with same name in JavaScript Promise API.

ERRORS

By default, a simple object, which is to be stringified into a string containing a short description of the error with the location of the error (e.g. Something's wrong at path/to/file.pl line 12345.\n), is used when the JavaScript Promise API would use a TypeError. The object is implementing the Perl Error Object Interface Level 1 <https://github.com/manakai/perl-web-dom/blob/master/lib/Web/DOM/Error.pod#error-object-api>.

By setting $Promise::CreateTypeError variable to a code reference, any value can be used as an exception instead of the string. The code or method is invoked with the short description as the first method argument ($_[1]) and is expected to return a value that is to be used as an exception. It is expected not to throw any exception.

EVENT LOOP

Fulfilled and rejected callbacks are expected to be invoked by queuing them to some kind of event scheduling mechanism.

By default, this is implemented using AnyEvent. By setting $Promise::Enqueue variable to a code reference, any event scheduling mechanism can be used instead. The code or method is invoked with the code reference as the first method argument ($_[1]). It is expected not to throw any exception. It is expected that the code reference is enqueued and to be invoked later.

If the AnyEvent default is unchanged and promises are used to write a standalone application, the condvar returned by the to_cv method of the last promise can be used to wait for receiving, which effectively invokes the main loop of the application:

use MyPromisedApp;
MyPromisedApp->some_process->then (sub {
  ...
})->then (sub {
  ...
})->to_cv->recv;

DEPENDENCY

The module requires Perl 5.8 or later and Carp (which is a core module).

By default the module also requires AnyEvent. However they are not required when event loop handlers are replaced as described in previous sections.

Otherwise the module has no dependency. The module can be used by simply copying the module file into your Perl execution environment, or by adding the Git repository as a submodule of your Perl application.

SEE ALSO

ECMAScript Language Specification <https://tc39.github.io/ecma262/#sec-promise-objects>.

There are a number of promise-based Perl modules. For convinience, the same Git repository as this module contains Promised::Flow, which abstracts common promise-based program control flows.

AbortController, AbortSignal.

HISTORY

This repository was originally located at <https://github.com/wakaba/perl-promise>, which has been transferred to the manaki project on October 7, 2021.

AUTHOR

Wakaba <wakaba@suikawiki.org>.

LICENSE

Copyright 2014-2021 Wakaba <wakaba@suikawiki.org>.

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

About

Promise in Perl


Languages

Language:Perl 99.2%Language:Makefile 0.8%