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