3. What’s Jscex
• JavaScript Computation EXpression
• A JavaScript language extension to help
programming in common scenarios
• A port of F# Computation Expression
• Inspired by the idea
• Design for JavaScript
4. What’s NOT Jscex
• Another language
• Jscex is 100% JavaScript
• A framework
• It’s a library, works with any libraries / frameworks
• A JavaScript engine / runtime
• Execute in any ECMAScript 3 engines
6. Bubble Sort
var compare = function (x, y) {
return x - y;
}
var swap = function (a, i, j) {
var t = a[x]; a[x] = a[y]; a[y] = t;
}
var bubbleSort = function (array) {
for (var x = 0; x < array.length; x++) {
for (var y = 0; y < array.length - x; y++) {
if (compare(array[y], array[y + 1]) > 0) {
swap(array, y, y + 1);
}
}
}
}
7. Animate it!
var compare = function (x, y, callback) { var innerLoop = function (array, x, y, callback) {
setTimeout(10, function () { if (y < array.length - x) {
callback(x - y); compare(array[y], array[y + 1], function (r) {
}); if (r > 0) {
} swap(array, y, y + 1, function () {
innerLoop(array, x, y + 1, callback);
var swap = function (a, i, j, callback) { });
var t = a[x]; a[x] = a[y]; a[y] = t; } else {
repaint(a); innerLoop(array, x, y + 1, callback);
}
setTimeout(20, callback); });
} } else {
callback();
var outerLoop = function (array, x, callback) { }
if (x < array) { }
innerLoop(array, x, 0, function () {
outerLoop(array, x + 1, callback); outerLoop(array, 0, function () {
}); console.log("done!");
} else { });
callback();
}
}
8. Animate it!
at?
var compare = function (x, y, callback) {
th
var innerLoop = function (array, x, y, callback) {
is
setTimeout(10, function () { if (y < array.length - x) {
callback(x - y); compare(array[y], array[y + 1], function (r) {
ll
}); if (r > 0) {
} swap(array, y, y + 1, function () {
e
innerLoop(array, x, y + 1, callback);
h
var swap = function (a, i, j, callback) { });
var t = a[x]; a[x] = a[y]; a[y] = t; } else {
e
repaint(a); innerLoop(array, x, y + 1, callback);
h
}
t
setTimeout(20, callback); });
t
} } else {
a
callback();
h
var outerLoop = function (array, x, callback) { }
if (x < array) { }
innerLoop(array, x, 0, function () {
W
outerLoop(array, x + 1, callback); outerLoop(array, 0, function () {
}); console.log("done!");
} else { });
callback();
}
}
9. Bubble Sort Animation
var compareAsync = eval(Jscex.compile("async", function (x, y) {
$await(Jscex.Async.sleep(10)); // each "compare" takes 10 ms.
return x - y;
}));
var swapAsync = eval(Jscex.compile("async", function (a, x, y) {
var t = a[x]; a[x] = a[y]; a[y] = t; // swap
repaint(a); // repaint after each swap
$await(Jscex.Async.sleep(20)); // each "swap" takes 20 ms.
}));
var bubbleSortAsync = eval(Jscex.compile("async", function (array) {
for (var x = 0; x < array.length; x++) {
for (var y = 0; y < array.length - x; y++) {
var r = $await(compareAsync(array[y], array[y + 1]));
if (r > 0) $await(swapAsync(array, y, y + 1));
}
}
}));
10. Bubble Sort Animation
var compareAsync = eval(Jscex.compile("async", function (x, y) {
$await(Jscex.Async.sleep(10)); // each "compare" takes 10 ms.
return x - y;
}));
var swapAsync = eval(Jscex.compile("async", function (a, x, y) {
var t = a[x]; a[x] = a[y]; a[y] = t; // swap
repaint(a); // repaint after each swap
$await(Jscex.Async.sleep(20)); // each "swap" takes 20 ms.
}));
var bubbleSortAsync = eval(Jscex.compile("async", function (array) {
for (var x = 0; x < array.length; x++) {
for (var y = 0; y < array.length - x; y++) {
var r = $await(compareAsync(array[y], array[y + 1]));
if (r > 0) $await(swapAsync(array, y, y + 1));
}
}
}));
13. Language Features
• Support almost all JavaScript constructs
• Loops: while / for / for...in / do
• Conditions: if / switch
• Error handling: try...catch...finally
• Others: return / break / continue / throw
• Not supported
• with block
• break / continue to label
• conditional break in switch block
• Nested functions
14. Language Semantics
• Keep all semantics as JavaScript
• Explicit “bind” operations (like $await)
• The only extension to the language
• Act like a method call
• Make clear which operation is “special”
15. Programming
Experiences
• Write, execute, debug as JavaScript
• Modify and take effects immediately
• No extra compilation process
• Code generation by JIT compiler as code runs
17. Code Locality is
Broken
• Used to expressing algorithms linearly
• Async requires logical division of algorithms
• Very difficult to
• Combine multiple asynchronous operations
• Deal with exceptions and cancellation
18. Asynchronous Function
// use async builder to execute the compiled code
var somethingAsync = eval(Jscex.compile("async",
function (...) {
// implementation
}
));
20. React!!!
function () {
var res = $await(<async work>);
}
an HTTP Request
an UI Event
a Timer Callback
a Query Response
a Web Service Response
an Agent Message
21. function () {
var img = $await(readAsync("http://..."));
console.log("loaded!");
$await(writeAsync("./files/..."));
console.log("saved!");
}
=
(function () {
var _b_ = Jscex.builders["async"];
return _b_.Start(this,
_b_.Delay(function () {
_b_.Bind(readAsync(...), function (img) {
console.log("loaded!");
return _b_.Bind(writeAsync(...), function () {
console.log("saved!");
return _b_.Normal();
});
});
})
);
})
22. Work with Express
var app = express.createServer();
app.get('/', function (req, res) {
/**
* Question: How to do async work here? e.g.:
*
* 1. Get multiple keys from database.
* 2. For each key, try get data from cache.
* If cache missed, get data from database.
* 3. Write a list of result to the response.
*
* Note: all "get" operations are asynchronous.
**/
});
app.listen(3000);
23. app.getAsync('/', eval(Jscex.compile("async", function (req, res) {
var keys = $await(db.getKeysAsync(...));
var results = [];
for (var i = 0; i < keys.length; i++) {
var r = $await(cache.getAsync(keys[i]));
if (!r) {
r = $await(db.getAsync(keys[i]));
}
results.push(r);
}
res.send(generateList(results));
})));
24. I/O Parallelism
• Software is often I/O bound
• Leveraging web services
• Working with data on disk
• Network and disk speeds increasing slower
• I/O resources are inherently parallel
• Huge opportunity for performance
25. Make Things Parallel
var getDataAsync = eval(Jscex.compile("async", function (key) {
var res = $await(cache.getAsync(key));
if (res) return res;
return $await(db.getAsync(key));
}));
app.getAsync('/', eval(Jscex.compile("async", function (req, res) {
var keys = $await(db.getKeysAsync(...));
// get tasks of “get data” (not started yet)
var tasks = keys.map(function (key) {
return getDataAsync(key);
});
// make requests in parallel
var results = $await(Jscex.Async.parallel(tasks));
res.send(generateList(results));
})));
26. Task Model
• Async library use a simple task model
• Easy to write bindings for async operations
• Parallel: $await(Jscex.Async.parallel(taskA, taskB))
• Series: $await(taskA.continueWith(taskB))
• The semantics of $await: wait a task to
complete
• Start the task if it’s not running
• Return immediately if it’s already completed
• We can start a task manually (if necessary)
• E.g. taskA.start(); $await(taskB); $await(taskA);
28. The Limitation of
Callback-based Model
// if the sequence of processing is important, how to keep it?
var i = 1;
conn.onAsync("data", eval(Jscex.compile("async", function () {
var id = i++;
$await(step1); console.log("step 1 - request " + id);
$await(step2); console.log("step 2 - request " + id);
/**
* A possible sequence (which is unacceptable):
* step 1 - request 1
* step 1 - request 2
* step 2 - request 2
* step 2 - request 1
**/
})));
29. Erlang-like Agent
var i = 0;
var agent = Agent.start(eval(Jscex.compile("async", function (mailbox) {
var id = i++;
var msg = $await(mailbox.receive());
$await(step1); console.log("step 1 - request " + id);
$await(step2); console.log("step 2 - request " + id);
})));
conn.on("data", function (data) {
// data would be queued in mailbox
agent.send(data);
});
32. AOT Compiler
// before AOT compilation
Agent.start(eval(Jscex.compile("async", function (mailbox) {
...
})));
// after AOT compilation
// independent of compiler scripts
// need a tiny library only (3kb when gzipped)
Agent.start((function (mailbox) {
var _b_ = Jscex.builders["async"];
return _b_.Start(this,
...
);
}));
33. Jscex Builders
• Compiler generates code into standard
patterns with a builder (name)
• A builder defines its name of the “bind” operation
• Execute with the standard methods
implemented in the builder
34. Not only for Async
// infinite fibonacci sequence
var fib = eval(Jscex.compile("seq", function () {
var i = 0, j = 1;
while (true) {
$yield(i); // the bind operation
var t = i;
i = j;
j += t;
}
}));
var iter = fib().skip(10).take(10);
while (iter.moveNext()) {
console.log(iter.current);
}
35. ... and Maybe Monad
var maybeFunc = function () {
var maybeA = getA();
if (maybeA == Maybe.None) return Maybe.None;
var maybeB = getB();
if (maybeB == Maybe.None) return Maybe.None;
return maybeA.value + maybeB.value;
}
// simplified version
var maybeFunc = eval(Jscex.compile("maybe", function () {
var a = $try(getA());
var b = $try(getB());
return a + b;
}));
37. Performance
• Function has “linear” and “async” parts
• Linear part: compiler keeps linear codes as much as
possible
• Async part: at the same level of hand-writing, callback-
based implementation
• An async operation always takes much
more time than a bunch of normal codes
• Jscex never becomes a performance issue / bottleneck
38. Code Generation
Patterns
• Code generation is direct and simple
• Map to original code easily
• Easy to debug: use “debugger” statement to pause or
add breakpoints in debuggers
• Based on standard methods
• Start, Delay, Combine
• Loop, Try
• Normal, Return, Break, Continue, Throw
• Bind