1Mojo::Promise(3) User Contributed Perl Documentation Mojo::Promise(3)
2
3
4
6 Mojo::Promise - Promises/A+
7
9 use Mojo::Promise;
10 use Mojo::UserAgent;
11
12 # Wrap continuation-passing style APIs with promises
13 my $ua = Mojo::UserAgent->new;
14 sub get_p {
15 my $promise = Mojo::Promise->new;
16 $ua->get(@_ => sub {
17 my ($ua, $tx) = @_;
18 my $err = $tx->error;
19 if (!$err || $err->{code}) { $promise->resolve($tx) }
20 else { $promise->reject($err->{message}) }
21 });
22 return $promise;
23 }
24
25 # Perform non-blocking operations sequentially
26 get_p('https://mojolicious.org')->then(sub {
27 my $mojo = shift;
28 say $mojo->res->code;
29 return get_p('https://metacpan.org');
30 })->then(sub {
31 my $cpan = shift;
32 say $cpan->res->code;
33 })->catch(sub {
34 my $err = shift;
35 warn "Something went wrong: $err";
36 })->wait;
37
38 # Synchronize non-blocking operations (all)
39 my $mojo = get_p('https://mojolicious.org');
40 my $cpan = get_p('https://metacpan.org');
41 Mojo::Promise->all($mojo, $cpan)->then(sub {
42 my ($mojo, $cpan) = @_;
43 say $mojo->[0]->res->code;
44 say $cpan->[0]->res->code;
45 })->catch(sub {
46 my $err = shift;
47 warn "Something went wrong: $err";
48 })->wait;
49
50 # Synchronize non-blocking operations (race)
51 my $mojo = get_p('https://mojolicious.org');
52 my $cpan = get_p('https://metacpan.org');
53 Mojo::Promise->race($mojo, $cpan)->then(sub {
54 my $tx = shift;
55 say $tx->req->url, ' won!';
56 })->catch(sub {
57 my $err = shift;
58 warn "Something went wrong: $err";
59 })->wait;
60
62 Mojo::Promise is a Perl-ish implementation of Promises/A+
63 <https://promisesaplus.com> and a superset of ES6 Promises
64 <https://duckduckgo.com/?q=n%20Promise>.
65
67 A promise is an object representing the eventual completion or failure
68 of a non-blocking operation. It allows non-blocking functions to return
69 values, like blocking functions. But instead of immediately returning
70 the final value, the non-blocking function returns a promise to supply
71 the value at some point in the future.
72
73 A promise can be in one of three states:
74
75 pending
76 Initial state, neither fulfilled nor rejected.
77
78 fulfilled
79 Meaning that the operation completed successfully.
80
81 rejected
82 Meaning that the operation failed.
83
84 A pending promise can either be fulfilled with a value or rejected with
85 a reason. When either happens, the associated handlers queued up by a
86 promise's "then" method are called.
87
89 Mojo::Promise implements the following attributes.
90
91 ioloop
92 my $loop = $promise->ioloop;
93 $promise = $promise->ioloop(Mojo::IOLoop->new);
94
95 Event loop object to control, defaults to the global Mojo::IOLoop
96 singleton. Note that this attribute is weakened.
97
99 Mojo::Promise inherits all methods from Mojo::Base and implements the
100 following new ones.
101
102 all
103 my $new = Mojo::Promise->all(@promises);
104
105 Returns a new Mojo::Promise object that either fulfills when all of the
106 passed Mojo::Promise objects have fulfilled or rejects as soon as one
107 of them rejects. If the returned promise fulfills, it is fulfilled with
108 the values from the fulfilled promises in the same order as the passed
109 promises.
110
111 all_settled
112 my $new = Mojo::Promise->all_settled(@promises);
113
114 Returns a new Mojo::Promise object that fulfills when all of the passed
115 Mojo::Promise objects have fulfilled or rejected, with hash references
116 that describe the outcome of each promise.
117
118 any
119 my $new = Mojo::Promise->any(@promises);
120
121 Returns a new Mojo::Promise object that fulfills as soon as one of the
122 passed Mojo::Promise objects fulfills, with the value from that
123 promise. If no promises fulfill, it is rejected with the reasons from
124 the rejected promises in the same order as the passed promises. Note
125 that this method is EXPERIMENTAL and might change without warning!
126
127 catch
128 my $new = $promise->catch(sub {...});
129
130 Appends a rejection handler callback to the promise, and returns a new
131 Mojo::Promise object resolving to the return value of the callback if
132 it is called, or to its original fulfillment value if the promise is
133 instead fulfilled.
134
135 # Longer version
136 my $new = $promise->then(undef, sub {...});
137
138 # Pass along the rejection reason
139 $promise->catch(sub {
140 my @reason = @_;
141 warn "Something went wrong: $reason[0]";
142 return @reason;
143 });
144
145 # Change the rejection reason
146 $promise->catch(sub {
147 my @reason = @_;
148 return "This is bad: $reason[0]";
149 });
150
151 clone
152 my $new = $promise->clone;
153
154 Return a new Mojo::Promise object cloned from this promise that is
155 still pending.
156
157 finally
158 my $new = $promise->finally(sub {...});
159
160 Appends a fulfillment and rejection handler to the promise, and returns
161 a new Mojo::Promise object resolving to the original fulfillment value
162 or rejection reason.
163
164 # Do something on fulfillment and rejection
165 $promise->finally(sub {
166 say "We are done!";
167 });
168
169 map
170 my $new = Mojo::Promise->map(sub {...}, @items);
171 my $new = Mojo::Promise->map({concurrency => 3}, sub {...}, @items);
172
173 Apply a function that returns a Mojo::Promise to each item in a list of
174 items while optionally limiting concurrency. Returns a Mojo::Promise
175 that collects the results in the same manner as "all". If any item's
176 promise is rejected, any remaining items which have not yet been mapped
177 will not be. Note that this method is EXPERIMENTAL and might change
178 without warning!
179
180 # Perform 3 requests at a time concurrently
181 Mojo::Promise->map({concurrency => 3}, sub { $ua->get_p($_) }, @urls)
182 ->then(sub{ say $_->[0]->res->dom->at('title')->text for @_ });
183
184 These options are currently available:
185
186 concurrency
187 concurrency => 3
188
189 The maximum number of items that are in progress at the same time.
190
191 new
192 my $promise = Mojo::Promise->new;
193 my $promise = Mojo::Promise->new(sub {...});
194
195 Construct a new Mojo::Promise object.
196
197 # Wrap a continuation-passing style API
198 my $promise = Mojo::Promise->new(sub {
199 my ($resolve, $reject) = @_;
200 Mojo::IOLoop->timer(5 => sub {
201 if (int rand 2) { $resolve->('Lucky!') }
202 else { $reject->('Unlucky!') }
203 });
204 });
205
206 race
207 my $new = Mojo::Promise->race(@promises);
208
209 Returns a new Mojo::Promise object that fulfills or rejects as soon as
210 one of the passed Mojo::Promise objects fulfills or rejects, with the
211 value or reason from that promise.
212
213 reject
214 my $new = Mojo::Promise->reject(@reason);
215 $promise = $promise->reject(@reason);
216
217 Build rejected Mojo::Promise object or reject the promise with one or
218 more rejection reasons.
219
220 # Longer version
221 my $promise = Mojo::Promise->new->reject(@reason);
222
223 resolve
224 my $new = Mojo::Promise->resolve(@value);
225 $promise = $promise->resolve(@value);
226
227 Build resolved Mojo::Promise object or resolve the promise with one or
228 more fulfillment values.
229
230 # Longer version
231 my $promise = Mojo::Promise->new->resolve(@value);
232
233 then
234 my $new = $promise->then(sub {...});
235 my $new = $promise->then(sub {...}, sub {...});
236 my $new = $promise->then(undef, sub {...});
237
238 Appends fulfillment and rejection handlers to the promise, and returns
239 a new Mojo::Promise object resolving to the return value of the called
240 handler.
241
242 # Pass along the fulfillment value or rejection reason
243 $promise->then(
244 sub {
245 my @value = @_;
246 say "The result is $value[0]";
247 return @value;
248 },
249 sub {
250 my @reason = @_;
251 warn "Something went wrong: $reason[0]";
252 return @reason;
253 }
254 );
255
256 # Change the fulfillment value or rejection reason
257 $promise->then(
258 sub {
259 my @value = @_;
260 return "This is good: $value[0]";
261 },
262 sub {
263 my @reason = @_;
264 return "This is bad: $reason[0]";
265 }
266 );
267
268 timer
269 my $new = Mojo::Promise->timer(5 => 'Success!');
270 $promise = $promise->timer(5 => 'Success!');
271 $promise = $promise->timer(5);
272
273 Create a new Mojo::Promise object with a timer or attach a timer to an
274 existing promise. The promise will be resolved after the given amount
275 of time in seconds with or without a value. Note that this method is
276 EXPERIMENTAL and might change without warning!
277
278 timeout
279 my $new = Mojo::Promise->timeout(5 => 'Timeout!');
280 $promise = $promise->timeout(5 => 'Timeout!');
281 $promise = $promise->timeout(5);
282
283 Create a new Mojo::Promise object with a timeout or attach a timeout to
284 an existing promise. The promise will be rejected after the given
285 amount of time in seconds with a reason, which defaults to "Promise
286 timeout". Note that this method is EXPERIMENTAL and might change
287 without warning!
288
289 wait
290 $promise->wait;
291
292 Start "ioloop" and stop it again once the promise has been fulfilled or
293 rejected, does nothing when "ioloop" is already running.
294
296 Mojolicious, Mojolicious::Guides, <https://mojolicious.org>.
297
298
299
300perl v5.32.0 2020-07-28 Mojo::Promise(3)