File Coverage

blib/lib/Mojo/AsyncAwait.pm
Criterion Covered Total %
statement 10 10 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 14 100.0


line stmt bran cond sub pod time code
1             package Mojo::AsyncAwait;
2              
3 9     9   3074697 use Carp ();
  9         62  
  9         183  
4 9     9   399 use Mojo::Loader;
  9         29482  
  9         276  
5 9     9   3399 use Import::Into;
  9         19327  
  9         1216  
6              
7             our $VERSION = '0.02';
8              
9             my $backend = $ENV{MOJO_ASYNCAWAIT_BACKEND} // '+Coro';
10             $backend =~ s/^\+/Mojo::AsyncAwait::Backend::/;
11             if(my $e = Mojo::Loader::load_class($backend)) {
12             Carp::croak(ref $e ? $e : "Could not find backend $backend. Perhaps you need to install it?");
13             }
14              
15 9     9   97 sub import { $backend->import::into(scalar caller) }
16              
17             1;
18              
19              
20             =encoding utf8
21              
22             =head1 NAME
23              
24             Mojo::AsyncAwait - An Async/Await implementation for Mojolicious
25              
26             =head1 SYNOPSIS
27              
28             use Mojolicious::Lite -signatures;
29             use Mojo::AsyncAwait;
30              
31             get '/' => async sub ($c) {
32              
33             my $mojo = await $c->ua->get_p('https://mojolicious.org');
34             my $cpan = await $c->ua->get_p('https://metacpan.org');
35              
36             $c->render(json => {
37             mojo => $mojo->result->code,
38             cpan => $cpan->result->code
39             });
40             };
41              
42             app->start;
43              
44             =head1 DESCRIPTION
45              
46             Async/await is a language-independent pattern that allows nonblocking
47             asynchronous code to be structured simliarly to blocking code. This is done by
48             allowing execution to be suspended by the await keyword and returning once the
49             promise passed to await has been fulfilled.
50              
51             This pattern simplies the use of both promises and nonblocking code in general
52             and is therefore a very exciting development for writing asynchronous systems.
53              
54             If you are going to use this module to create async controllers actions in
55             L applications (as seen in the L) before Mojolicious
56             version 8.28, you are highly encouraged to also use
57             L in order to properly handle exceptions
58             in your action.
59              
60             =head1 GOALS
61              
62             The primary goal of this module is to provide a useful Async/Await
63             implementation for users of the Mojolicious ecosystem. It is for this reason
64             that L is used when new promises are created. Because this is
65             the primary goal, the intention is for it to remain useful even as other goals
66             are considered.
67              
68             Secondarily, it is intended to be a testbed for early implementations of
69             Async/Await in the Perl 5 language. It is for this reason that the
70             implementation details are intended to be replaceable. The result should
71             hopefully still be backwards compatible, mostly because the interface is so
72             simple. After all, it is just two keywords.
73              
74             Of course, I always intend as much as possible that Mojolicious-focused code is
75             as useful as practically possible for the broader Perl 5 ecosystem. It is for
76             this reason that while this module returns Ls, it can accept any
77             then-able (read: promise) which conforms enough to the Promises/A+ standard.
78             The Promises/A+ standard is intended to increase the interoperability of
79             promises, and while that line becomes more gray in Perl 5 where we don't have a
80             single ioloop implementation, we try our best.
81              
82             Finally the third goal is to improve the mobility of the knowledge of this
83             pattern between languages. Users of Javascript probably are already familiar
84             with this patthern; when coming to Perl 5 they will want to continue to use it.
85             Likewise, as Perl 5 users take on new languages, if they are familiar with
86             common patterns in their new language, they will have an easier time learning.
87             Having a useable Async/Await library in Perl 5 is key to keeping Perl 5
88             relevent in moderning coding.
89              
90             =head1 BACKENDS
91              
92             This module actually does very little on its own, it simply loads and imports
93             backend implementations of Async/Await. The reason to use this module really
94             would be to use current default implementation without regards to what that
95             implementation is nor how it works.
96              
97             When it is loaded, the C is checked, if not set then
98             the current default is used.
99              
100             # From environment
101             BEGIN{ $ENV{MOJO_ASYNCAWAIT_BACKEND} = '+CoolBackend' }
102             use Mojo::AsyncAwait;
103              
104             # Currently provided default
105             use Mojo::AsyncAwait;
106              
107             The backend is specified either as a fully qualified module name, e.g.
108             C or using the C<+> as a shortcut for
109             C, e.g. C<+CoolBackend> which would mean exactly
110             the same as the former.
111              
112             =head1 CAVEATS
113              
114             First and foremost, this is all a little bit crazy. Please consider carefully
115             before using this code in production.
116              
117             While many languages have async/await as a core language feature, currently in
118             Perl we must rely on modules that provide the mechanism of suspending and
119             resuming execution.
120              
121             The default implementation relies on L which does some very magical
122             things to the Perl interpreter. Other less magical implementations are in the
123             works however none are available yet. As available implementations change or
124             stabilize, that default may be changed. Backend implementations may be added or
125             even be spun off. If your application depends on the backend implementation,
126             you may import it manually or use the described mechanisms to load it. In that
127             case you should be sure to add the backend to your dependency list in case it
128             is spun off in the future.
129              
130             Also note that while a L-based implementation need not rely on L
131             being called directly from an L function, it is currently prohibitied
132             because it is likely that other/future implementations will rely on that
133             behavior and thus it should not be relied upon.
134              
135             =head1 KEYWORDS
136              
137             Regardless of backend, L provides two keywords (i.e.
138             functions), both exported by default. Depending on backend, their exact
139             behavior might change slightly, however, implementers should attempt to follow
140             the api described here as closely as possible.
141              
142             Some backends may allow additional options to be passed to the keywords; those
143             options should be kept minimal and if possible follow the conventions described
144             in L. This generic document will not describe
145             those additional options.
146              
147             =head2 async
148              
149             my $sub = async sub { ... };
150              
151             The async keyword wraps a subroutine as an asynchronous subroutine which is
152             able to be suspended via L. The return value(s) of the subroutine, when
153             called, will be wrapped in a L.
154              
155             The async keyword must be called with a subroutine reference, which will be the
156             body of the async subroutine.
157              
158             Note that the returned subroutine reference is not invoked for you.
159             If you want to immediately invoke it, you need to so manually.
160              
161             my $promise = async(sub{ ... })->();
162              
163             If called with a preceding name, the subroutine will be installed into the
164             current package with that name.
165              
166             async installed_sub => sub { ... };
167             installed_sub();
168              
169             Unlike the case of an anonymous wrapped async subroutine reference described
170             above, if the subroutine is installed, nothing is returned.
171              
172             =head2 await
173              
174             my $tx = await Mojo::UserAgent->new->get_p('https://mojolicious.org');
175             my @results = await (async sub { ...; return @async_results })->();
176              
177             The await keyword suspends execution of an async sub until a promise is
178             fulfilled, returning the promise's results. In list context all promise results
179             are returned. For ease of use, in scalar context the first promise result is
180             returned and the remainder are discarded.
181              
182             If the value passed to await is not a promise (defined as having a C
183             method), it will be wrapped in a Mojo::Promise for consistency. This is mostly
184             inconsequential to the user.
185              
186             Note that await can only take one promise as an argument. If you wanted to
187             await multiple promises you probably want L or less likely
188             L.
189              
190             my $results = await Mojo::Promise->all(@promises);
191              
192             =head1 AUTHORS
193              
194             Joel Berger
195              
196             Marcus Ramberg
197              
198             =head1 CONTRIBUTORS
199              
200             Sebastian Riedel
201              
202             =head1 ADDITIONAL THANKS
203              
204             Matt S Trout (mst)
205              
206             Paul Evans (LeoNerd)
207              
208             John Susek
209              
210             =head1 COPYRIGHT AND LICENSE
211              
212             Copyright (C) 2018, L and L.
213              
214             This program is free software, you can redistribute it and/or modify it under
215             the terms of the Artistic License version 2.0.
216              
217             =head1 SEE ALSO
218              
219             L
220              
221             L
222              
223             L
224              
225             L
226              
227             L
228              
229             L
230              
231             L
232              
233             =cut
234