代码改变世界

Wind.js的一些简单使用和说明

2012-09-05 10:07  飞魚  阅读(5799)  评论(0编辑  收藏  举报

零零碎碎的看了一些关于wind(原名jscex)的说明和例子,其实也没太明白,这里写一些个人看法...

wind.js,一个可以让你已同步方式编写代码异步执行的lib,可作用于前后端js环境...

如何编写?

var printAsync = eval(Wind.compile("async", function (text) {

  $await(Wind.Async.sleep(1000));

  console.log(text);

  return text;
}));

定义一个wind方法要包装在eval(Wind.compile("async", …)中...

var task = printAsync("Hello World");

调用它后返回的是一个task对象,需要调用start方法执行

tack.start();

下面已浏览器为例,下载wind资源

页面中依次引入

<script src="wind-core.js" type="text/javascript"></script>
<script src="wind-compiler.js" type="text/javascript"></script>
<script src="wind-builderbase.js" type="text/javascript"></script>
<script src="wind-async.js" type="text/javascript"></script>

<script type="text/javascript">
var printAsync = eval(Wind.compile("async", function (text) {
$await(Wind.Async.sleep(1000));
console.log(text);
return "aaa";
}));
var task = printAsync("Hello World");
task.start();
console.log(task);
</script>

在浏览器控制台的打印结果...

// Original: 

function (text) {
            $await(Wind.Async.sleep(1000));
            console.log(text);
            return "aaa";
        }



// Compiled: 

/* async << function (text) { */   (function (text) {
                                       var _builder_$0 = Wind.builders["async"];
                                       return _builder_$0.Start(this,
                                           _builder_$0.Delay(function () {
/*     $await(Wind.Async.sleep(1000)); */      return _builder_$0.Bind(Wind.Async.sleep(1000), function () {
/*     console.log(text); */                       console.log(text);
/*     return "aaa"; */                            return _builder_$0.Return("aaa");
                                               });
                                           })
                                       );
/* } */                            })
//@ sourceURL=wind/0_anonymous.js

 wind-core.js:158
Async.Task
_delegate: function (t) {
_eventManager: null
_result: "aaa"
status: "succeeded"
__proto__: Object
 test.htm:19
injectScript startLiveReload init
Hello World 

从打印注释可以看出wind把原来的方法编译成了自己需要的形式..

同时也看到了我们自己打印的text值为Hello World和task对象结构..

其中_result为我们返回的值,status为succeeded...

我们写的函数里唯一不同的是用了$await(Wind.Async.sleep(1000));

Wind.Async.sleep(1000)是wind自身为我们提供的,从意思可以看出来是停止1秒,它返回的是一个tesk对象...

$await接受task类型参数,它等待此task执行结束并返回结果,如果此task没有启动就调用start启动执行...

从这可以看出我们写的wind方法可以嵌套在另一个wind方法内,通过$await命令来执行并等待结果...

例如

var printAllAsync = eval(Wind.compile("async"function (texts) {

for (var i = 0; i < texts.length; i++) {

$await(printAsync(texts[i]));

}

}));

当然它还提供了一些其他方法...但是这之前还是大体了一下它的结构和为什么会这样...

wind现在主要提供了5个模块,从命名基本可以看出是干什么的...

它的结构组织方式也比较好懂,建议从底到上阅读...

为了更好的看出各模块的引用顺序,依赖说明和选项信息,这里已node环境为例...

首先看wind-core.js

   if (isCommonJS) {
        Wind = module.exports;
        init();
    } else if (isAmd) {
        define("wind-core", function () {
            Wind = { };
            init();
            return Wind;
        });
    } else {
        // Get the global object.
        var Fn = Function, global = Fn('return this')();
    
        if (global.Wind) {
            throw new Error("There's already a Wind root here, please load the component only once.");
        }
        
        Wind = global.Wind = { };
        init();
    }

每个模块底部都有这么一个东西,基本就是判断在哪种环境下,然后执行init初始,由于这里是node环境,所以每次只关注

if (isCommonJS) {
        Wind = module.exports;
        init();
    } 

这里即可..

输出wind执行init函数

var init = function () {
Wind.logger = new Logger();
Wind.Logging = {
Logger: Logger,
Level: Level
};

Wind._ = _;
Wind.modules = { core: { name: "core", version: "0.7.0" } };
Wind.binders = { };
Wind.builders = { };
Wind.define = defineModule;
};

给wind添加一个核心方法

wind-compiler.js模块

if (isCommonJS) {
try {
Wind = require("./wind-core");
} catch (ex) {
Wind = require("wind-core");
}

defineModule();
}
可以看到它会自动加载core,
然后执行defineModule

var defineModule = function () {
Wind.define({
name: "compiler",
version: "0.7.1",
require: isCommonJS && require,
dependencies: { core: "~0.7.0" },
init: function () {
Wind.parse = parse;
Wind.compile = compile;
}
});
}

这里看到了调用了wind的define方法.然后你跟进去就会发现,有autoloads就自动加载,有依赖就检测是否引用..主要就是执行init这里给wind对象又安插了parse和compile方法,主要就是靠它俩实现wind方法变成成正常方法...

 然后你每个模块的底部都看看就知道了

wind-builderbase模块依赖core,wind-async和wind-promise都依赖wind-builderbase

wind-builderbase提供了一些编译后的基本方法...

下面看看wind-async中的代码...

var defineModule = function () {
Wind.define({
name: "async",
version: "0.7.0",
require: isCommonJS && require,
autoloads: [ "builderbase" ],
dependencies: { builderbase: "~0.7.0" },
init: function () {

_ = Wind._;

_.each(Wind.BuilderBase.prototype, function (m, fn) {
AsyncBuilder.prototype[m] = fn;
});

Wind.Async = Async;

Wind.binders["async"] = "$await";
Wind.builders["async"] = new AsyncBuilder();
}
});
}

 把BuilderBase的方法都安装到AsyncBuilder中..

 从这里可以看出Wind.binders["async"] = "$await";
Wind.builders["async"] = new AsyncBuilder();

 之前写的

var printAsync = eval(Wind.compile("async", function (text) {

  $await(Wind.Async.sleep(1000));

  console.log(text);

  return text;
}));

async和await应该都是这里定义的...

从前面打印的结果

/* async << function (text) { */   (function (text) {
                                       var _builder_$0 = Wind.builders["async"];
                                       return _builder_$0.Start(this,
                                           _builder_$0.Delay(function () {
/*     $await(Wind.Async.sleep(1000)); */      return _builder_$0.Bind(Wind.Async.sleep(1000), function () {
/*     console.log(text); */                       console.log(text);
/*     return "aaa"; */                            return _builder_$0.Return("aaa");
                                               });
                                           })
                                       );
/* } */                            })
//@ sourceURL=wind/0_anonymous.js
可以看到Delay,Return等方法都是BuilderBase中的方法...
而wind-async和wind-promise都会有一个XXXBuilder对象如PromiseBuilder..都会有Start和Bind方法,
编译后调用的Start和Bind就是这俩个方法...
从wind-async和wind-promise这俩个中的Start和Bind

Start: function (_this, task) {
return Task.create(function (t) {
task.next(_this, function (type, value, target) {
if (type == "normal" || type == "return") {
t.complete("success", value);
} else if (type == "throw") {
t.complete("failure", value);
} else {
throw new Error("Unsupported type: " + type);
}
});
});
}

这个基本一样..在type == "normal" || type == "return")是触发我们传进去的函数就哦了

Bind也一样 按它的结构在绑定在某一时刻调用函数触发下一个任务即可..

其实wind-async里的Start和Bind为什么要这样写都是和Task对象有关的,从这个模块的源码中就可以看到Task的定义,了解更多的用法..

比如

var create = Task.create = function (delegate) {
return new Task(delegate);
}

 Task.prototype.on = Task.prototype.addEventListener = function () {

等等..

下面看下fromCallback

var fromCallback = Binding.fromCallback = function (fn) {
var callbackArgNames = collectCallbackArgNames(arguments);

return function () {
var _this = this;
var args = collectArgs(arguments, fn.length - 1);

return Task.create(function (t) {
args.push(function (result) {
if (callbackArgNames) {
var data = {};
for (var i = 0; i < callbackArgNames.length; i++) {
data[callbackArgNames[i]] = arguments[i];
}

t.complete("success", data);
} else {
t.complete("success", result);
}
});

fn.apply(_this, args);
});
};
};

把一个异步方法变成wind方法其实很简单就包装一下返回一个task对象即可..

可以看到它最后返回一个Task对象,当用$await或start时执行...

它主要解决异步返回的方法..形如下面

function ajax(str, func) {
var n = parseInt(Math.random() * 10) * 1000;
str += "ASYNC";
setTimeout(function() {
func(str);
}, n);
}

var syncAjax = Wind.Async.Binding.fromCallback(ajax);

我们在浏览器以定时器模仿一个异步...

function ajax(str, func) {
var n = parseInt(Math.random() * 10) * 1000;
str += "ASYNC";
setTimeout(function() {
func(str);
}, n);
}
var syncAjax = Wind.Async.Binding.fromCallback(ajax);

var printAsync = eval(Wind.compile("async", function(text) {
var a = $await(syncAjax(123));
console.log(a);
return a;
}));
console.log(printAsync().start());

看看这个代码执行了什么

首先启动printAsync,

里面用await启动syncAjax(123),

首先看看syncAjax(123)是什么,

我们绑定syncAjax 后syncAjax就是返回的一个函数

跟踪 var callbackArgNames = collectCallbackArgNames(arguments);,由于传的就一个函数所以callbackArgNames 为null,所以不用管,

然后调用并传进123,

跟踪

var _this = this;//应该是window
var args = collectArgs(arguments, fn.length - 1);

args即为参数数组[123],

$await调用syncAjax(123)执行

args.push(function(result) {
if (callbackArgNames) {
var data = {};
for (var i = 0; i < callbackArgNames.length; i++) {
data[callbackArgNames[i]] = arguments[i];
}

t.complete("success", data);
} else {
t.complete("success", result);
}
});

看到args为俩个参数[123,func]

fn.apply(_this, args);即为

ajax(123,func),

所以完成时t.complete("success", result);触发...

这时应该会调用AsyncBuilder中的Bind直接返回给结果..

下面看一下执行的结果

Async.Task
  1. _delegatefunction (t) {
  2. _eventManagernull
  3. _result"123ASYNC"
  4. status"succeeded"
  5. __proto__Object
HTMLPage.htm:39
injectScript startLiveReload init
123ASYNC

 

暂时写到这吧。