jscex: write sexy javascript (中文)

43
Jscex Write Sexy JavaScript 赵劼 - 盛大创新院 - 2011.5

Upload: jeffz

Post on 06-May-2015

13.352 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Jscex: Write Sexy JavaScript (中文)

JscexWrite Sexy JavaScript

赵劼 - 盛大创新院 - 2011.5

Page 2: Jscex: Write Sexy JavaScript (中文)

关于我• 赵劼 / 老赵 / Jeffrey Zhao / 赵姐夫

• 日写代码三百行,不辞长作程序员• 博客:http://blog.zhaojie.me/

• 微博:@老赵

• F#, JavaScript, Scala, C#, Python, .NET, Mono...

• 痛恨Java语言

Page 3: Jscex: Write Sexy JavaScript (中文)

Jscex是什么?

• JavaScript Computation EXpression

• JavaScript语言扩展,用于某些常见场景下的编程

• F#计算表达式特性的JavaScript移植• 受“计算表达式”特性启发• 为JavaScript设计,基于JavaScript实现

Page 4: Jscex: Write Sexy JavaScript (中文)

Jscex不是什么?

• 另一种语言• Jscex是百分百的JavaScript

• 框架• Jscex是类库,能够与几乎任何类库/框架一起使用

• JavaScript引擎/运行时• 在任何ECMAScript 3上执行

Page 5: Jscex: Write Sexy JavaScript (中文)

浅尝辄止

Page 6: Jscex: Write Sexy JavaScript (中文)

冒泡排序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); } } }}

Page 7: Jscex: Write Sexy JavaScript (中文)

做成动画var compare = function (x, y, callback) { setTimeout(10, function () { callback(x - y); });}

var swap = function (a, i, j, callback) { var t = a[x]; a[x] = a[y]; a[y] = t; repaint(a); setTimeout(20, callback);}

var outerLoop = function (array, x, callback) { if (x < array) { innerLoop(array, x, 0, function () { outerLoop(array, x + 1, callback); }); } else { callback(); }}

var innerLoop = function (array, x, y, callback) { if (y < array.length - x) { compare(array[y], array[y + 1], function (r) { if (r > 0) { swap(array, y, y + 1, function () { innerLoop(array, x, y + 1, callback); }); } else { innerLoop(array, x, y + 1, callback); } }); } else { callback(); }}

outerLoop(array, 0, function () { console.log("done!");});

Page 8: Jscex: Write Sexy JavaScript (中文)

做成动画var compare = function (x, y, callback) { setTimeout(10, function () { callback(x - y); });}

var swap = function (a, i, j, callback) { var t = a[x]; a[x] = a[y]; a[y] = t; repaint(a); setTimeout(20, callback);}

var outerLoop = function (array, x, callback) { if (x < array) { innerLoop(array, x, 0, function () { outerLoop(array, x + 1, callback); }); } else { callback(); }}

var innerLoop = function (array, x, y, callback) { if (y < array.length - x) { compare(array[y], array[y + 1], function (r) { if (r > 0) { swap(array, y, y + 1, function () { innerLoop(array, x, y + 1, callback); }); } else { innerLoop(array, x, y + 1, callback); } }); } else { callback(); }}

outerLoop(array, 0, function () { console.log("done!");});

这TMD是什么啊!

Page 9: Jscex: Write Sexy JavaScript (中文)

冒泡排序动画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)); } }}));

Page 10: Jscex: Write Sexy JavaScript (中文)

冒泡排序动画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)); } }}));

Page 11: Jscex: Write Sexy JavaScript (中文)

首要设计原则

Page 12: Jscex: Write Sexy JavaScript (中文)

为JavaScript程序员保留一切

• 语言特性• 语言语义• 编程体验

Page 13: Jscex: Write Sexy JavaScript (中文)

语言特性• 支持几乎所有JavaScript语言功能

• 循环:while / for / for...in / do

• 判断:if / switch

• 错误处理:try...catch...finally

• 其他:return / break / continue / throw

• 不支持的语言特性• with块• 带标签的break和continue

• switch内带条件的break

• 嵌套函数

Page 14: Jscex: Write Sexy JavaScript (中文)

语言语义

• 保持完整的JavaScript语义

• 独立的“bind”操作(例如$await)• 语言里的唯一扩展• 表现形式为“方法调用”

• 清楚表明“特殊”的操作

Page 15: Jscex: Write Sexy JavaScript (中文)

编程体验

• 如JavaScript一般编写、执行、调试

• 修改后立即生效• 没有额外的编译步骤

• 代码执行过程中由JIT编译器生成代码

Page 16: Jscex: Write Sexy JavaScript (中文)

异步编程十分困难

Page 17: Jscex: Write Sexy JavaScript (中文)

破坏代码局部性

• 程序员习惯线性地表达算法• 异步代码将逻辑拆分地支离破碎• 难以

• 异步操作之间的协作及组合• 处理异常及取消

Page 18: Jscex: Write Sexy JavaScript (中文)

异步函数

// 使用异步构造器执行编译后的代码var somethingAsync = eval(Jscex.compile("async", function (...) { // 实现 }));

Page 19: Jscex: Write Sexy JavaScript (中文)

function () { var res = $await(<async work>);}

响应

Page 20: Jscex: Write Sexy JavaScript (中文)

function () { var res = $await(<async work>);}

响应

HTTP请求UI事件时钟回调查询响应

Web Service响应代理消息

Page 21: Jscex: Write Sexy JavaScript (中文)

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(); }); }); }) );})

Page 22: Jscex: Write Sexy JavaScript (中文)

使用Express框架var app = express.createServer();

app.get('/', function (req, res) { /** * 问题:如何进行异步操作?例如: * * 1. 从数据库中获取多个键值。 * 2. 对于每个键,从缓存中获取数据。 * 如果缓存失效,则从数据库里获取数据。 * 3. 将结果列表发送至res中。 * * 注意:所有的“获取”操作都是异步的。 **/});

app.listen(3000);

Page 23: Jscex: Write Sexy JavaScript (中文)

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));})));

Page 24: Jscex: Write Sexy JavaScript (中文)

I/O并行

• 许多程序是I/O密集型应用• 使用Web服务• 使用磁盘上的数据

• 网络和磁盘速度发展很慢• I/O资源天然可以并行

• 提高性能的关键方式

Page 25: Jscex: Write Sexy JavaScript (中文)

并行执行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(...));

// 获取“请求数据”的任务(尚未执行) var tasks = keys.map(function (key) { return getDataAsync(key); }); // 同时发起所有异步任务 var results = $await(Jscex.Async.parallel(tasks)); res.send(generateList(results));})));

Page 26: Jscex: Write Sexy JavaScript (中文)

任务模型• 异步类库使用一种十分简单的任务模型

• 可以轻松地将各种异步操作融入这种模型• 并行:$await(Jscex.Async.parallel(taskA, taskB))

• 串行:$await(taskA.continueWith(taskB))

• $await语义:等待任务完成• 如果任务尚未执行,则启动• 如果任务已经结束,则立即返回

• 在需要的时候可以手动启动任务• 例如:taskA.start(); $await(taskB); $await(taskA);

Page 27: Jscex: Write Sexy JavaScript (中文)

高级异步模式

Page 28: Jscex: Write Sexy JavaScript (中文)

异步回调模型的限制// 如果处理顺序十分重要,那么如何保持这些顺序?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); /** * 一种可能的顺序(但不可接受) * step 1 - request 1 * step 1 - request 2 * step 2 - request 2 * step 2 - request 1 **/})));

Page 29: Jscex: Write Sexy JavaScript (中文)

Erlang形式的代理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) { // 数据会缓存在mailbox队列中 agent.send(data);});

Page 30: Jscex: Write Sexy JavaScript (中文)

Jscex组件

Page 31: Jscex: Write Sexy JavaScript (中文)

语言与类库• 编译器(语言扩展)

• JIT:在运行时生成代码(用于开发环境)• AOT:在运行之前生成代码(用于生成环境)

• 构造器(类库)• 异步构造器:简化异步编程• 序列构造器:延迟加载的迭代器(如Python,C#,

JavaScript 1.7等等)• 更多…

Page 32: Jscex: Write Sexy JavaScript (中文)

AOT编译器// AOT编译前Agent.start(eval(Jscex.compile("async", function (mailbox) { ...})));

// AOT编译后// 可以独立于编译器脚本执行// 只需极小的核心类库(gzip后大约3kb)Agent.start((function (mailbox) { var _b_ = Jscex.builders["async"]; return _b_.Start(this, ... );}));

Page 33: Jscex: Write Sexy JavaScript (中文)

Jscex构造器

• 编译器根据指定的构造器(名称)将代码编译为标准模式• 构造器指定自己需要的“绑定”操作名称

• 由定义在构造器上的标准方法执行代码

Page 34: Jscex: Write Sexy JavaScript (中文)

不仅仅是异步编程// 无限的菲波纳契数列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);}

Page 35: Jscex: Write Sexy JavaScript (中文)

…还有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;}

// 简化后的版本var maybeFunc = eval(Jscex.compile("maybe", function () { var a = $try(getA()); var b = $try(getB()); return a + b;}));

Page 36: Jscex: Write Sexy JavaScript (中文)

深入Jscex

Page 37: Jscex: Write Sexy JavaScript (中文)

性能

• 异步函数包含“线性部分”及“异步部分”• 线性部分:编译器尽可能保留原代码的线性部分• 异步部分:与基于回调函数的手动实现相近

• 单个异步操作耗时远胜大段线性代码• Jscex不会成为程序的性能问题 / 瓶颈

Page 38: Jscex: Write Sexy JavaScript (中文)

代码生成模式• 代码生成模式简单而直接

• 能够轻松映射至原有代码• 易于调试:使用“debugger”语句暂停代码,或在调试器中设置断点

• 基于标准方法• Start, Delay, Combine

• Loop, Try

• Normal, Return, Break, Continue, Throw

• Bind

Page 39: Jscex: Write Sexy JavaScript (中文)

调试浏览器脚本

Page 40: Jscex: Write Sexy JavaScript (中文)

调试Node.js脚本

Page 41: Jscex: Write Sexy JavaScript (中文)

立即尝试

• 基于BSD协议发布

• 站点• 英文:https://github.com/JeffreyZhao/jscex

• 中文:http://www.sndacode.com/projects/jscex

Page 42: Jscex: Write Sexy JavaScript (中文)

Q & A

Page 43: Jscex: Write Sexy JavaScript (中文)

谢谢