Feb 21, 2007
遅延評価を使ってSjaxをAjaxに変換する方法
継続を使ってSjaxをAjaxに簡単に変換する方法http://d.hatena.ne.jp/llamerada/20070220/1171984586
を見て。こんなのはどうだろう。
ユーザーからの入力や、非同期のHTTPリクエストなんかを、具体化されてないオブジェクトとして捉えて、それらを受け取った関数側が遅延オブジェクトを具体化するためのリクエストを投げて再試行する。ネストが深くならないですむ、同期処理で書く場合との変更点が少ない、あるいは完全に差異を無くすことができる。
alert(args)のコメントを外せば、引数が具体化されていく様子が分かるはず。
Function.prototype.receive_lazy = function(){
var orig = this;
return function(){
var thisObj = this;
var me = arguments.callee;
var args = Array.prototype.slice.apply(arguments);
// alert(args);
function retry(i, as_force){
return function(arg){
if(!isLazy(args[i])) args[i] = args[i].value;
if(as_force && typeof arg == "function"){
arg(me.apply(thisObj, args));
} else {
return me.apply(thisObj, args)
}
}
}
for(var i=0;i<args.length;i++){
if(isLazy(args[i])){
args[i].force(retry(i));
return {isLazy:true, force: retry(i, true)}
}
}
return orig.apply(this, args);
}
};
function isLazy(obj){
return typeof obj == "object" && obj.isLazy
}
// ここからが実際に記述する部分
function fetch(path, length, offset, cont){
var range = ["bytes=" + offset + "-" + (offset + length - 1)].join("");
var options = {
method: "get",
onComplete: function(request){cont(request.responseText);},
requestHeaders: ["Range", range]
}
new Ajax.Request(path, options);
}
fetch = fetch.receive_lazy();
function lazy_fetch(path, length, offset, inflate){
var lazy_object = {
isLazy: true,
force: function(callback){
fetch(path, length, offset, function(responseText){
lazy_object.isLazy = false;
lazy_object.value =
(typeof inflate == "function")
? inflate(responseText)
: responseText;
callback(lazy_object.value);
});
}
};
return lazy_object;
};
function fetch_data(){
var path = "/data.txt";
var offset = lazy_fetch(path, 4, 0, parseInt);
var length = lazy_fetch(path, 4, 4, parseInt);
return lazy_fetch(path, length, offset);
}
// ここでalertも変形させてしまえば同期処理のコードとほとんど同じになる
fetch_data().force(alert)
処理の流れは、
- lazyなオブジェクトを引数に受け取ったら
-- 引数を具体化するためのforceメソッドを呼び出す
-- オブジェクトが具体化されたら、関数を再度実行する
- 全ての引数が具体化されたらオリジナルの関数に処理を引き渡す
Function.prototypeにreceive_lazyメソッドを加えて、あらかじめ遅延評価な変数を受け取れるように関数を変形しておく必要がある。考え方としては、コードを書くときに非同期処理を完全に意識しないで済むようにしたい。非同期に合わせて書くのではなく、同期処理のつもりで書いたコードが、いつのまにやら非同期処理になってる、というのがやりたい。
Edit this entry...
wikieditish message: Ready to edit this entry.
A quick preview will be rendered here when you click "Preview" button.