Professional Documents
Culture Documents
Function (Content) (Processcontent (Content) ) )
Function (Content) (Processcontent (Content) ) )
Function (Content) (Processcontent (Content) ) )
say#e$$o()
Dow0 how do we do this in an asynchronous style2 *e may try to do this:
for(!ar i " %; i & ar.$en'th; i(() {
fetchURL(ar)i*, function(content) {
processContent(content);
);
say#e$$o();
6ut that?s not going to work. 5irst of all0 U3Ls would now be fetched in parallel /which is kind of cool
actually0 but not what we wanted1 and second0 the hello?ing happens too early0 not after we?re done
with the fetching. *hat we would need to do is something like this:
ar.re!erse();
function +one() {
say#e$$o();
function fetch,ne() {
!ar ur$ " ar.pop();
fetchURL(ar)i*, function(content) {
processContent(content);
if(ar.$en'th """ %) {
+one();
e$se {
fetch,ne();
);
if(ar.$en'th """ %) {
+one();
e$se {
fetch,ne();
@uchE .he idea here is to use the array as a stack. *e define a function that processes one U3L. .he
function pops an element off the array0 fetches the U3L and when done processes it0 it checks if the
stack is empty0 if so0 it says hello /+one function10 if not0 it recursively calls itself to process the next
element /the new top1 in the array.
Luckily0 this type of code can be wrapped in a nicer looking 7B!0 which allows you to rewrite this code
as:
async-or.ach(ar, function(ur$, ca$$/ac0) {
fetchURL(ar)i*, function(content) {
processContent(content);
ca$$/ac0();
);
, function() {
say#e$$o();
);
6ut still0 wouldn?t you prefer the synchronous version2
Enter mobl
Fven though mobl compiles down to 9avascript0 you do not have to do this style of asynchronous
programming. *hy2 6ecause the compiler is able to automatically transform synchronous style
programs into asynchronous style programs. Ges. 7utomatically0 the compiler does exactly what ! +ust
did by hand.
Mobl libraries wrap asynchronous 9avascript 7B!s as synchronous 7B!s. 7 simple example. 4ow do
you sleep in a 9avascript program for $ second. .here?s no s$eep function0 and even if there would
be0 it would block the thread and render the browser unusable. !f you want something to happen in
about $ second0 what you do is you use 9avscript?s set1imeout0 right2
set1imeout(function() {
a$ert('2 secon+ passe+3');
, 2%%%);
7s you can tell0 this is another example of an asynchronous call. 4ere?s what that code looks like in
mobl:
s$eep(2%%%);
a$ert(42 secon+ passe+34);
Let?s have a look at the signature of s$eep in the mobl standard library:
e5terna$ function s$eep(ms : 6um) : !oi+
.his signature tells us two things:
$. .here is a function named s$eep that takes a single /numeric1 argument and returns nothing
/void1.
#. .his function is asynchronous.
Fvery external function is assumed to be asynchronous unless stated otherwise /using the sync
keyword0 e.g. e5terna$ sync function1. 6eing asynchronous means that in addition to the
arguments specified in the signature0 a callback function is provided that is to be called when the
function completes.
.his signature by itself does not do anything0 it +ust tells the mobl compiler that <there exists a function
with this name in this module=. .he compiler then assumes there?s a definition for it elsewhere0 in this
case in native 9avascript:
&7a!ascript8
99ns.s$eep " function(ms, ca$$/ac0) {
set1imeout(ca$$/ac0, ms);
;
&/7a!ascript8
Mobl enables you to include fragments of <native= 9avascript in-between &7a!ascript8 tags. 99ns
is a reference to the module?s namespace ob+ect. !f a function0 control or screen is defined in a module
it is not put in a global scope0 but in a module ob+ect named after the module. 5or instance for the
mo/$ module this ob+ect is named mo/$0 for mo/$::ui::'eneric it?s mo/$.ui.'eneric0 a
reference to the ob+ect can be obtained using the 99ns shortcut.
.he implementation of s$eep takes0 as predicted0 two arguments: the number of milliseconds to wait0
and what to do next /a callback function1. !t basically delegates this call directly to set1imeout0 +ust
switching the argument order.
7lright0 so what happens when we call s$eep from mobl2 *hat is the 9avascript code generated by
the following mobl code2
s$eep(2%%%);
a$ert(42 secon+ passe+34);
Hleaned-up a little bit0 the resulting 9avascript looks as follows:
mo/$.s$eep(2%%%, function() {
mo/$.a$ert(42 secon+ passe+34);
);
.he transformation performed by the compiler here is called the continuation-passing style
transformation0 a pretty well-known transformation in academia0 although not often applied outside
languages like cheme.
.hanks to the HB transform0 mobl code can be written in a synchronous style0 while still maintaining
the advantages of asynchronous code0 i.e. being non-blocking. @ne drawback is that writing code that
re,uires concurrent execution > for instance0 fetching all the U3Ls at the same time > is more
difficult to express. Mobl does have the async block for this purpose0 which conceptually executes its
body <on a different thread of execution=0 i.e. the code after it can run in parallel with the code inside it:
async {
s$eep(2%%%);
a$ert(4:'m $ast4);
a$ert(4:'m