零零碎碎的看了一些關於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直接返回給結果..
下面看一下執行的結果
暫時寫到這吧。
