零零碎碎的看了一些关于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直接返回给结果..
下面看一下执行的结果
暂时写到这吧。