1Promises(3)           User Contributed Perl Documentation          Promises(3)
2
3
4

NAME

6       Promises - An implementation of Promises in Perl
7

VERSION

9       version 1.04
10

SYNOPSIS

12         use AnyEvent::HTTP;
13         use JSON::XS qw[ decode_json ];
14         use Promises qw[ collect deferred ];
15
16         sub fetch_it {
17             my ($uri) = @_;
18             my $d = deferred;
19             http_get $uri => sub {
20                 my ($body, $headers) = @_;
21                 $headers->{Status} == 200
22                     ? $d->resolve( decode_json( $body ) )
23                     : $d->reject( $body )
24             };
25             $d->promise;
26         }
27
28         my $cv = AnyEvent->condvar;
29
30         collect(
31             fetch_it('http://rest.api.example.com/-/product/12345'),
32             fetch_it('http://rest.api.example.com/-/product/suggestions?for_sku=12345'),
33             fetch_it('http://rest.api.example.com/-/product/reviews?for_sku=12345'),
34         )->then(
35             sub {
36                 my ($product, $suggestions, $reviews) = @_;
37                 $cv->send({
38                     product     => $product,
39                     suggestions => $suggestions,
40                     reviews     => $reviews,
41                 })
42             },
43             sub { $cv->croak( 'ERROR' ) }
44         );
45
46         my $all_product_info = $cv->recv;
47

DESCRIPTION

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

FUTURE BACKWARDS COMPATIBILITY WARNING

55       The version of this module is being bumped up to 0.90 as the first step
56       towards 1.0 in which the goal is to have full Promises/A+ spec
57       compatibility. This is a departure to the previous goal of being
58       compatible with the Promises/A spec, this means that behavior may
59       change in subtle ways (we will attempt to document this completely and
60       clearly whenever possible).
61
62       It is HIGHLY recommended that you test things very thoroughly before
63       upgrading to this version.
64

BACKWARDS COMPATIBILITY WARNING

66       In version up to and including 0.08 there was a bug in how rejected
67       promises were handled. According to the spec, a rejected callback can:
68
69       •   Rethrow the exception, in which case the next rejected handler in
70           the chain would be called, or
71
72       •   Handle the exception (by not "die"ing), in which case the next
73           resolved handler in the chain would be called.
74
75       In previous versions of Promises, this last step was handled
76       incorrectly: a rejected handler had no way of handling the exception.
77       Once a promise was rejected, only rejected handlers in the chain would
78       be called.
79
80   Relation to the various Perl event loops
81       This module is actually Event Loop agnostic, the SYNOPSIS above uses
82       AnyEvent::HTTP, but that is just an example, it can work with any of
83       the existing event loops out on CPAN. Over the next few releases I will
84       try to add in documentation illustrating each of the different event
85       loops and how best to use Promises with them.
86
87   Relation to the Promise/A spec
88       We are, with some differences, following the API spec called
89       "Promise/A" (and the clarification that is called "Promise/A+") which
90       was created by the Node.JS community. This is, for the most part, the
91       same API that is implemented in the latest jQuery and in the YUI
92       Deferred plug-in (though some purists argue that they both go it wrong,
93       google it if you care). We differ in some respects to this spec, mostly
94       because Perl idioms and best practices are not the same as Javascript
95       idioms and best practices. However, the one important difference that
96       should be noted is that "Promise/A+" strongly suggests that the
97       callbacks given to "then" should be run asynchronously (meaning in the
98       next turn of the event loop). We do not do this by default, because
99       doing so would bind us to a given event loop implementation, which we
100       very much want to avoid. However we now allow you to specify an event
101       loop "backend" when using Promises, and assuming a Deferred backend has
102       been written it will provide this feature accordingly.
103
104   Using a Deferred backend
105       As mentioned above, the default Promises::Deferred class calls the
106       success or error then() callback synchronously, because it isn't tied
107       to a particular event loop.  However, it is recommended that you use
108       the appropriate Deferred backend for whichever event loop you are
109       running.
110
111       Typically an application uses a single event loop, so all Promises
112       should use the same event-loop. Module implementers should just use the
113       Promises class directly:
114
115           package MyClass;
116           use Promises qw(deferred collect);
117
118       End users should specify which Deferred backend they wish to use. For
119       instance if you are using AnyEvent, you can do:
120
121           use Promises backend => ['AnyEvent'];
122           use MyClass;
123
124       The Promises returned by MyClass will automatically use whichever event
125       loop AnyEvent is using.
126
127       See:
128
129
130        Promises::Deferred::AE
131
132
133        Promises::Deferred::AnyEvent
134
135
136        Promises::Deferred::EV
137
138
139        Promises::Deferred::Mojo
140
141
142        Promises::Deferred::IO::Async
143
144   Relation to Promises/Futures in Scala
145       Scala has a notion of Promises and an associated idea of Futures as
146       well. The differences and similarities between this module and the
147       Promises found in Scalar are highlighted in depth in a cookbook entry
148       below.
149
150   Cookbook
151       Promises::Cookbook::GentleIntro
152        Read this first! This cookbook provides a step-by-step explanation of
153        how Promises work and how to use them.
154
155       Promises::Cookbook::SynopsisBreakdown
156        This breaks down the example in the SYNOPSIS and walks through much of
157        the details of Promises and how they work.
158
159       Promises::Cookbook::TIMTOWTDI
160        Promise are just one of many ways to do async programming, this entry
161        takes the Promises SYNOPSIS again and illustrates some counter
162        examples with various modules.
163
164       Promises::Cookbook::ChainingAndPipelining
165        One of the key benefits of Promises is that it retains much of the
166        flow of a synchronous program, this entry illustrates that and
167        compares it with a synchronous (or blocking) version.
168
169       Promises::Cookbook::Recursion
170        This entry explains how to keep the stack under control when using
171        Promises recursively.
172
173       Promises::Cookbook::ScalaFuturesComparison
174        This entry takes some examples of Futures in the Scala language and
175        translates them into Promises. This entry also showcases using
176        Promises with Mojo::UserAgent.
177

EXPORTS

179       "deferred"
180           This just creates an instance of the Promises::Deferred class it is
181           purely for convenience.
182
183           Can take a coderef, which will be dealt with as a "then" argument.
184
185               my $promise = deferred sub {
186                   ... do stuff ...
187
188                   return $something;
189               };
190
191               # equivalent to
192
193               my $dummy = deferred;
194
195               my $promise = $dummy->then(sub {
196                   ... do stuff ...
197
198                   return $something;
199               });
200
201               $dummy->resolve;
202
203       resolved( @values )
204           Creates an instance of Promises::Deferred resolved with the
205           provided @values. Purely a shortcut for
206
207               my $promise = deferred;
208               $promise->resolve(@values);
209
210       rejected( @values )
211           Creates an instance of Promises::Deferred rejected with the
212           provided @values. Purely a shortcut for
213
214               my $promise = deferred;
215               $promise->reject(@values);
216
217       collect( @promises )
218           Accepts a list of Promises::Promise objects and then returns a
219           Promises::Promise object which will be called once all the
220           @promises have completed (either as an error or as a success).
221
222           The eventual result of the returned promise object will be an array
223           of all the results of each of the @promises in the order in which
224           they where passed to "collect" originally, wrapped in arrayrefs, or
225           the first error if at least one of the promises fail.
226
227           If "collect" is passed a value that is not a promise, it'll be
228           wrapped in an arrayref and passed through.
229
230               my $p1 = deferred;
231               my $p2 = deferred;
232               $p1->resolve(1);
233               $p2->resolve(2,3);
234
235               collect(
236                   $p1,
237                   'not a promise',
238                   $p2,
239               )->then(sub{
240                   print join ' : ', map { join ', ', @$_ } @_; # => "1 : not a promise : 2, 3"
241               })
242
243       collect_hash( @promises )
244           Like "collect", but flatten its returned arrayref into a single
245           hash-friendly list.
246
247           "collect_hash" can be useful to a structured hash instead of a long
248           list of promise values.
249
250           For example,
251
252             my $id = 12345;
253
254             collect(
255                 fetch_it("http://rest.api.example.com/-/product/$id"),
256                 fetch_it("http://rest.api.example.com/-/product/suggestions?for_sku=$id"),
257                 fetch_it("http://rest.api.example.com/-/product/reviews?for_sku=$id"),
258             )->then(
259                 sub {
260                     my ($product, $suggestions, $reviews) = @_;
261                     $cv->send({
262                         product     => $product,
263                         suggestions => $suggestions,
264                         reviews     => $reviews,
265                         id          => $id
266                     })
267                 },
268                 sub { $cv->croak( 'ERROR' ) }
269             );
270
271           could be rewritten as
272
273             my $id = 12345;
274
275             collect_hash(
276                 id          => $id,
277                 product     => fetch_it("http://rest.api.example.com/-/product/$id"),
278                 suggestions => fetch_it("http://rest.api.example.com/-/product/suggestions?for_sku=$id"),
279                 reviews     => fetch_it("http://rest.api.example.com/-/product/reviews?for_sku=$id"),
280             )->then(
281                 sub {
282                     my %results = @_;
283                     $cv->send(\%results);
284                 },
285                 sub { $cv->croak( 'ERROR' ) }
286             );
287
288           Note that all promise values of the key/value pairs passed to
289           "collect_hash" must return a scalar or nothing, as returning more
290           than one value would mess up the returned hash format. If a promise
291           does return more than one value, "collect_hash" will consider it as
292           having failed.
293
294           If you know that a promise can return more than one value, you can
295           do:
296
297               my $collected = collect_hash(
298                   this => $promise_returning_scalar,
299                   that => $promise_returning_list->then(sub{ [ @_ ] } ),
300               );
301

SEE ALSO

303   Promises in General
304       You're Missing the Point of Promises
305       <http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/>
306       Systems Programming at Twitter
307       <http://monkey.org/~marius/talks/twittersystems/>
308       SIP-14 - Futures and Promises <http://docs.scala-
309       lang.org/sips/pending/futures-promises.html>
310       Promises/A+ spec <http://promises-aplus.github.io/promises-spec/>
311       Promises/A spec <http://wiki.commonjs.org/wiki/Promises/A>
312
313   Perl Alternatives
314       Future
315       Mojo::Promise
316           Part of the Mojolicious package.
317
318       Promise::ES6
319       Promise::Tiny
320       AnyEvent::XSPromises
321       Promise::XS
322

AUTHOR

324       Stevan Little <stevan.little@iinteractive.com>
325
327       This software is copyright (c) 2020, 2019, 2017, 2014, 2012 by Infinity
328       Interactive, Inc.
329
330       This is free software; you can redistribute it and/or modify it under
331       the same terms as the Perl 5 programming language system itself.
332
333
334
335perl v5.38.0                      2023-07-21                       Promises(3)
Impressum