每周优秀代码赏析—Jscex内核【一】
2011-11-24 08:49 【当耐特】 阅读(5231) 评论(14) 编辑 收藏 举报一.简介
Jscex is JavaScript implementation of F#'s Computation Expressions.
它的灵感的源于F#,它为JavaScript语言提供了一个monadic扩展。Jscex完全使用JavaScript编写,能够在任意支 持ECMAScript 3的引擎里使用(例如各浏览器或Node.js)。Jscex的JIT编译器能在运行时将JavaScript代码编译成Monad形式,无需额外编译步 骤,并内置异步编程类库,可以大大简化JavaScript下的异步编程体验。
二.原理探析
先揭开Jscex 内核之前我们先体验一下世界上最简单的一个 Jscex例子:
var i = 0; var countAsync = eval(Jscex.compile("async", function () { while (true) { i++; document.getElementById("show").innerHTML = i; $await(Jscex.Async.sleep(1000)); } })) countAsync().start();
一个计数器,从0开始每秒钟加1并显示出来。
然后我们把countAsync alert出来,看看Jscex把它compile成什么个样子:
function () { var $$_builder_$$_0 = Jscex.builders["async"]; return $$_builder_$$_0.Start(this, $$_builder_$$_0.Loop( function () { return true; }, null, $$_builder_$$_0.Delay(function () { i++; (document.getElementById("show")).innerHTML = i; return $$_builder_$$_0.Bind(Jscex.Async.sleep(1000), function () { return $$_builder_$$_0.Normal(); }); }), false ) ); }
一个匿名函数,然后用eval().start()执行该匿名函数。
那么上面还能拆开吗?如果作为一个纯粹的.NET或者JAVA程序员,看这段代码肯定很费劲,因为funciton里套funciton,return套return.
如果你知道javascript的执行顺序的话,上面的函数是还可以拆的:
var count = 0; function doCount() { count++; document.getElementById("clock").innerHTML = count; } var $$_builder_$$_0 = Jscex.builders["async"]; var delayCount = $$_builder_$$_0.Delay(function () { doCount(); return $$_builder_$$_0.Bind(Jscex.Async.sleep("1000"), function () { return $$_builder_$$_0.Normal(); }); }); var loopCount = $$_builder_$$_0.Loop( function () { return true; }, null, delayCount, false ); var countAsync = $$_builder_$$_0.Start(this, loopCount); countAsync.start();
这样视乎就很清楚它的执行顺序了~~~!
从上面的代码,我们可以看得出来:我们要做的事情就是:加1显示然后停一秒···加1显示然后停一秒····无限循环下去
我们发生的事情generator就是:
var delayCount = $$_builder_$$_0.Delay(function () { doCount(); return $$_builder_$$_0.Bind(Jscex.Async.sleep("1000"), function () { return $$_builder_$$_0.Normal(); }); });
我们要循环的就是delayCount,所以我们把它放到一个loop当中去:
var loopCount = $$_builder_$$_0.Loop( function () { return true; }, null, delayCount, false );
其中,第一个参数就是while(true),他标志这函数什么时候退出循环。所以比如while(i<3), 它就会编译成function(){return i<3;}
然后:
var countAsync = $$_builder_$$_0.Start(this, loopCount);
这行代码的主要作用是 把这个loop作为一个task赋给Jscex.Async.Task的_delegate,
可想而知,在这种架构的基础上,可以轻松实现N个loop,就有了异步队列~~~~
比如:
var executeAsyncQueue = eval(Jscex.compile("async", function () { while (true) { $await(countAsync()) $await(otherAsync()) $await(Jscex.Async.sleep(1000)); } })) executeAsyncQueue().start();
最后,执行countAsync ().start().整个流程就是这样子的,但是到现在为止,我们还没有进入Jscex内核当中去看一看它是怎么实现这些循环和中转的······
或者你根据上面的思路写出一个伪Jscex出来?我想这个写的过程可以帮你更好的理解Jscex的模式。
请关注: