-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.html
215 lines (162 loc) · 8.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
<html>
<head>
<title>Er.js: Erlang-in-JavaScript</title>
<style>
DIV { margin-left: 15%; margin-right: 15% }
</style>
</head>
<body>
<div align="center">
<h1>Er.js: Erlang-in-JavaScript</h1>
<h2>Erlang-style concurrency with JavaScript 1.7</h2>
<h3>
<a href="https://raw.githubusercontent.com/orph/erjs/master/er.js">Download Er.js</a> |
<a href="https://htmlpreview.github.io/?https://github.com/orph/erjs/blob/master/test.html">See it in action</a>
</h3>
</div>
<hr/>
<div>
<h3>About</h3>
<p>Er.js piggybacks on Neil Mix’s Thread.js
which fakes threading in JavaScript 1.7 using coroutines and nested generator
continuations. The goal is to replicate Erlang’s concurrent lockless
process model and message-passing APIs in JavaScript.</p>
<h3>Running Concurrently</h3>
<p>Running a JavaScript function in the background is easy with Er.js:</p>
<pre><big><strong>Er.spawn</strong>(myBackgroundFunction);</big></pre>
<p><code>Er.spawn</code> starts a new Er.js process running
<code>myBackgroundFunction</code>, and returns its process id. </p>
<p>Because processes are really coroutines, you have to call <code>yield</code>
before any function which might block. Calling <code>yield</code> will create a
continuation trampoline that can be rerun by Er.js when it’s time for the
process to continue executing. For example:</p>
<pre><big>function myBackgroundFunction() {
// Wait for 4 seconds
<strong>yield Er.sleep</strong>(4000);
// Do other things…
}</big></pre>
<h3>Sending Messages</h3>
<p>In Erlang and Er.js, each process has a built-in message queue that other
processes use to send it messages. Posting to the message queue never blocks
the caller, and the destination process for the message can read them off the
queue whenever it wants. Messages are just regular associative arrays, similar
to hashtables, which are easy to create in JavaScript. For example:</p>
<pre><big><strong>Er.send</strong>(myPid, { Hello: new Date(), From: Er.pid() });</big></pre>
<p>Here, <code>myPid</code> is assumed to be the process id from some former
call to <code>Er.spawn</code>. This call sends a message with the keys
“Hello” and “From”. <code>Hello</code> is a
<code>Date</code> object with the current date, and <code>From</code> is the
process id of the current process, which can always be fetched with
<code>Er.pid()</code>. Passing the current pid means the <code>myPid</code>
process can send us messages in return, since we’ve told it who we
are.</p>
<h3>Receiving & Pattern Matching</h3>
<p>When <code>myBackgroundFunction</code> wants to read off its message queue,
it calls the <code>Er.receive</code> function, telling it the kind of message
it’s interested in, and a function to call when such a message is
received. Interest in a message is expressed using a message pattern which,
just like the messages themselves, is a simple hash table.</p>
<pre><big><strong>yield Er.receive</strong>({ Hello: Date, From: _ }, // pattern
function(msg) { // handler
log(”Hello=” + msg.Hello);
log(”From=” + msg.From);
});</big></pre>
<p>This matches any message in the current process’s queue which has a
<code>Hello</code> key with a <code>Date</code> object as the value, and with a
<code>From</code> key with any value. Explicit value matching for e.g. number
and string literals and DOM elements is also possible. The “_” for
the <code>From</code> key means that any value is accepted. There are a few
other matching rules as well that make this a very powerful but simple message
dispatching mechanism.</p>
<p>If a message in the process queue matches a pattern passed to
<code>Er.receive</code>, it is passed to the handler function found in the
argument list following the pattern. The handler can look up the key values it
needs in order to act on the message. It can also send messages to other
processes, spawn new processes, receive queued messages or perform other work.
</p>
<p>Because the <code>Er.receive</code> call doesn’t finish until a message
matching one of patterns is received and handled, we put a <code>yield</code> in
front of the call to avoid blocking other processes.</p>
<h4>Linked Processes</h4>
<p>When a process finishes or exits, it automatically sends a message to any
processes which link to it. Linking is done by passing a pid to
<code>Er.link</code>. The sent message is of the form:</p>
<pre><big>{ Signal: Er.Exit, From: exiting_pid, Reason: reason }</big></pre>
<p>The <code>Reason</code> value comes either from the exiting process calling
<code>Er.exit(reason)</code>, or just <code>throw</code>'ing the reason as an
exception. If the linking process does not handle this message, it will exit
itself, sending exit messages to its own linked processes. This allows for
simple process chaining and failure handling.</p>
<h4>Message Multicast</h4>
<p>Er.js processes can also register to receive messages sent to a given name,
using <code>Er.register(name)</code>. Registered names can be passed as the
first argument to <code>Er.send</code>. Multiple processes can register for the
same name, and they will all receive a message sent to that name, allowing for
simple multi-casting.</p>
<h3>Concurrent AJAX with Er.Ajax</h3>
<p>XmlHttpRequest, AJAX and JSON integrate nicely with the process and
message-passing model, allowing processes to avoid asynchronous JavaScript and
callbacks.</p>
<p>Instead, using message-passing and concurrency, Er.js makes network access
transparent, without blocking other processes or interactivity:</p>
<pre><big>var txt = <strong>yield Er.Ajax.get</strong>("http://beatniksf.com/erjs/index.html");
alert("Fetched Content: " + txt);</big></pre>
<p>Under the covers, this is accomplished using <code>Er.Ajax.start</code>,
which handles asynchronous XmlHttpRequest internals and uses
<code>Er.send</code> to tell the current process about download progress and
completion.</p>
<p><code>Er.Ajax.get</code> and others (<code>post</code>, <code>json</code>,
etc) are implemented by yielding execution until the final message from
<code>Er.Ajax.start</code> is received. If the message indicates success, the
response text is returned to the caller, otherwise the failure message is
thrown:</p>
<pre><big>function myGet(url) {
<strong>Er.Ajax.start</strong>(url);
<strong>yield Er.receive</strong>({ Url: url, Success: true, Text: String, _:_ },
function(msg) { <strong>return msg.Text;</strong> },
{ Url: url, Success: false, Text: String, _:_ },
function(msg) { <strong>throw msg;</strong> });
}</big></pre>
<h3>Er.DOM Event Handling</h3>
<p>As with remote resources, Er.js can concurrently listen for DOM Events, and
once received insert them into the listening process's message queue. The
following demonstrates a simple wrapper, <code>Er.DOM.Receive</code>, which
subscribes to a named event on a DOM element and calls <code>Er.receive</code>
to await its delivery:</p>
<pre><big>var event = <strong>yield Er.DOM.receive</strong>(document, "click");
</big></pre>
<p>Note: The best approach to handling DOM manipulation and eventing with Er.js
is still under investigation. For instance, <code>document</code> above might
alternately refer to an an element's id or multiple elements using a CSS
selector.</p>
<h3>Future Work</h3>
<p>Er.js will wrap certain long-running asynchronous JavaScript calls in
synchronous yielding wrappers so that processes can avoid convoluted
asynchronous code.</p>
<h4>JSON-based Remote Procedure Calls</h4>
Like Erlang itself, Er.js will enable easy interaction with concurrent processes
running on remote nodes. Using JSON and XML, messages can be sent to and
received from remote servers using the same API as locally running concurrent
processes:
<pre><big>var rpc = <strong>Er.spawn</strong>("http://www.beatniksoftware.com/echo");
...
<strong>Er.send</strong>(rpc, { Echo: "This is the echo payload" });
<strong>yield Er.receive</strong>({ EchoResponse: String },
function (msg) {
alert("Got Echo response: " + msg.EchoResponse);
});</big></pre>
<h4>Native Threading</h4>
<p>It would also be interesting to explore the use of native threads for running
processes, leveraging e.g. Google Gears' <a
href="http://code.google.com/apis/gears/api_workerpool.html">WorkerPools</a> if
available on the client.</p>
</div>
<hr/>
<div align="center">
<p>
Er.js is from <a href="mailto:alexgraveley@gmail.com">Alex
Graveley</a> (<a href="http://alexgraveley.com">www</a>).
</p>
</div>
</body>
</html>