Your SlideShare is downloading. ×

Jscex: Write Sexy JavaScript

9,697

Published on

Published in: Technology, Business
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
9,697
On Slideshare
0
From Embeds
0
Number of Embeds
11
Actions
Shares
0
Downloads
61
Comments
0
Likes
3
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. JscexWrite Sexy JavaScript Zhao Jie - SNDA - May 2011
  • 2. About Me• / / Jeffrey Zhao /• Programmer• Blogger - http://blog.zhaojie.me/• Twitter: @jeffz_cn• F#, JavaScript, Scala, C#, Python, .NET, Mono...• Java (as a language) hater
  • 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
  • 5. Taste a Bit
  • 6. Bubble Sortvar 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); hvar 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(); hvar 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 Animationvar 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 Animationvar 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)); } }}));
  • 11. Design Principle #1
  • 12. Keep Everything forJavaScript Programmer• Language features• Language semantics• Programming experiences
  • 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 statement • break / continue to label • conditional break in switch statement• 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
  • 16. Async Programming is Difficult
  • 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 } ));
  • 19. React!!!function () { var res = $await(<async work>);}
  • 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 Expressvar 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 Parallelvar 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);
  • 27. AdvancedAsync Patterns
  • 28. The Limitation ofCallback-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 Agentvar 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);});
  • 30. Jscex Components
  • 31. Language & Libraries• Compiler (language extension) • JIT: generate code at runtime (development) • AOT: generate code before runtime (production)• Builders (libraries) • Async: simplfied async programming • Sequense: generator for lazy iterator (Py, C#, JS 1.7) • more...
  • 32. AOT Compiler// before AOT compilationAgent.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 sequencevar 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 Monadvar 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 versionvar maybeFunc = eval(Jscex.compile("maybe", function () { var a = $try(getA()); var b = $try(getB()); return a + b;}));
  • 36. Jscex Internals
  • 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
  • 39. Debug Browser Scripts
  • 40. Debug Node.js Scripts
  • 41. Try it NOW• Release under BSD license• https://github.com/JeffreyZhao/jecex
  • 42. Q &A
  • 43. Thanks

×