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('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. Note that this method is
117 EXPERIMENTAL and might change without warning!
118
119 any
120 my $new = Mojo::Promise->any(@promises);
121
122 Returns a new Mojo::Promise object that fulfills as soon as one of the
123 passed Mojo::Promise objects fulfills, with the value from that
124 promise. If no promises fulfill, it is rejected with the reasons from
125 the rejected promises in the same order as the passed promises. Note
126 that this method is EXPERIMENTAL and might change without warning!
127
128 catch
129 my $new = $promise->catch(sub {...});
130
131 Appends a rejection handler callback to the promise, and returns a new
132 Mojo::Promise object resolving to the return value of the callback if
133 it is called, or to its original fulfillment value if the promise is
134 instead fulfilled.
135
136 # Longer version
137 my $new = $promise->then(undef, sub {...});
138
139 # Pass along the rejection reason
140 $promise->catch(sub {
141 my @reason = @_;
142 warn "Something went wrong: $reason[0]";
143 return @reason;
144 });
145
146 # Change the rejection reason
147 $promise->catch(sub {
148 my @reason = @_;
149 return "This is bad: $reason[0]";
150 });
151
152 clone
153 my $new = $promise->clone;
154
155 Return a new Mojo::Promise object cloned from this promise that is
156 still pending.
157
158 finally
159 my $new = $promise->finally(sub {...});
160
161 Appends a fulfillment and rejection handler to the promise, and returns
162 a new Mojo::Promise object resolving to the original fulfillment value
163 or rejection reason.
164
165 # Do something on fulfillment and rejection
166 $promise->finally(sub {
167 say "We are done!";
168 });
169
170 map
171 my $new = Mojo::Promise->map(sub {...}, @items);
172 my $new = Mojo::Promise->map({concurrency => 3}, sub {...}, @items);
173
174 Apply a function that returns a Mojo::Promise to each item in a list of
175 items while optionally limiting concurrency. Returns a Mojo::Promise
176 that collects the results in the same manner as "all". If any item's
177 promise is rejected, any remaining items which have not yet been mapped
178 will not be. Note that this method is EXPERIMENTAL and might change
179 without warning!
180
181 # Perform 3 requests at a time concurrently
182 Mojo::Promise->map({concurrency => 3}, sub { $ua->get_p($_) }, @urls)
183 ->then(sub{ say $_->[0]->res->dom->at('title')->text for @_ });
184
185 These options are currently available:
186
187 concurrency
188 concurrency => 3
189
190 The maximum number of items that are in progress at the same time.
191
192 new
193 my $promise = Mojo::Promise->new;
194 my $promise = Mojo::Promise->new(sub {...});
195
196 Construct a new Mojo::Promise object.
197
198 # Wrap a continuation-passing style API
199 my $promise = Mojo::Promise->new(sub {
200 my ($resolve, $reject) = @_;
201 Mojo::IOLoop->timer(5 => sub {
202 if (int rand 2) { $resolve->('Lucky!') }
203 else { $reject->('Unlucky!') }
204 });
205 });
206
207 race
208 my $new = Mojo::Promise->race(@promises);
209
210 Returns a new Mojo::Promise object that fulfills or rejects as soon as
211 one of the passed Mojo::Promise objects fulfills or rejects, with the
212 value or reason from that promise.
213
214 reject
215 my $new = Mojo::Promise->reject(@reason);
216 $promise = $promise->reject(@reason);
217
218 Build rejected Mojo::Promise object or reject the promise with one or
219 more rejection reasons.
220
221 # Longer version
222 my $promise = Mojo::Promise->new->reject(@reason);
223
224 resolve
225 my $new = Mojo::Promise->resolve(@value);
226 $promise = $promise->resolve(@value);
227
228 Build resolved Mojo::Promise object or resolve the promise with one or
229 more fulfillment values.
230
231 # Longer version
232 my $promise = Mojo::Promise->new->resolve(@value);
233
234 then
235 my $new = $promise->then(sub {...});
236 my $new = $promise->then(sub {...}, sub {...});
237 my $new = $promise->then(undef, sub {...});
238
239 Appends fulfillment and rejection handlers to the promise, and returns
240 a new Mojo::Promise object resolving to the return value of the called
241 handler.
242
243 # Pass along the fulfillment value or rejection reason
244 $promise->then(
245 sub {
246 my @value = @_;
247 say "The result is $value[0]";
248 return @value;
249 },
250 sub {
251 my @reason = @_;
252 warn "Something went wrong: $reason[0]";
253 return @reason;
254 }
255 );
256
257 # Change the fulfillment value or rejection reason
258 $promise->then(
259 sub {
260 my @value = @_;
261 return "This is good: $value[0]";
262 },
263 sub {
264 my @reason = @_;
265 return "This is bad: $reason[0]";
266 }
267 );
268
269 timer
270 my $new = Mojo::Promise->timer(5 => 'Success!');
271 $promise = $promise->timer(5 => 'Success!');
272 $promise = $promise->timer(5);
273
274 Create a new Mojo::Promise object with a timer or attach a timer to an
275 existing promise. The promise will be resolved after the given amount
276 of time in seconds with or without a value. Note that this method is
277 EXPERIMENTAL and might change without warning!
278
279 timeout
280 my $new = Mojo::Promise->timeout(5 => 'Timeout!');
281 $promise = $promise->timeout(5 => 'Timeout!');
282 $promise = $promise->timeout(5);
283
284 Create a new Mojo::Promise object with a timeout or attach a timeout to
285 an existing promise. The promise will be rejected after the given
286 amount of time in seconds with a reason, which defaults to "Promise
287 timeout". Note that this method is EXPERIMENTAL and might change
288 without warning!
289
290 wait
291 $promise->wait;
292
293 Start "ioloop" and stop it again once the promise has been fulfilled or
294 rejected, does nothing when "ioloop" is already running.
295
297 Mojolicious, Mojolicious::Guides, <https://mojolicious.org>.
298
299
300
301perl v5.30.1 2020-01-30 Mojo::Promise(3)