代码改变世界

每周优秀代码赏析—Jscex内核【一】

2011-11-24 08:49  【当耐特】  阅读(5231)  评论(14编辑  收藏  举报

一.简介

Jscex is JavaScript implementation of F#'s Computation Expressions.

image

它的灵感的源于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的模式。

请关注:

每周优秀代码赏析—Jscex内核【二】