ただ生きることよりルール
じわじわくる!!
じわじわくる!!
http://svn.coderepos.org/share/lang/javascript/jquery-deferred/sample.html
http://jquery.com/plugins/project/deferred
いろいろサンプル書いてつかいみちを考えているとたのしい。
var list = [];
list.push($.get("a.html").next(function (data) { return data.match(/<title>([^<]+)<\/title>/) } ));
list.push($.get("b.txt" ).next(function (data) { return data.match(/##\s*([^<]+)\s*##/) } ));
list.push($.getJSON("c.json").next(function (data) { return data.title } ));
parallel(list).next(function (values) {
print("Titles "+values.join(", "));
});みたい書ける。たのしい。(うえのコードがうごくかはためしてない)
それぞれ、べつべつのフォーマットのリソースをとってくる。タイトルを抽出するところまでは個々の Deferred が処理して、そいつらを parallel (DeferredList) であつめてくる。
でもそういうふつうの (謎) 非同期処理より、ループの分割のほうがおもしろい。
loop({begin: 1, end:100, step:10}, function (n, o) {
print(["Processing devided loop:n=", n].join(""));
for (var i = 0; i < o.step; i++) {
var j = n + i;
print(j);
}
});
function print (m) { $("#loop-code1").append("\n// "+m) }1 から 100 までをループする。ただし最大 10 個に制限して分割してループする (o.step を条件にしているのは、境界付近でよしなにするため。最後 (o.last == true) 以外は常に渡した step と一緒)。定期的にブラウザに処理がもどるので固まったようにならない (100 ぐらいじゃ固まらないけど)。固まりさえしなければある程度時間がかかってもストレスがたまらないから嬉しい。
ディレイいれながらループも簡単にかける
loop(5, function (i, o) {
print(i);
return o.last? i : wait(1);
}).
next(function (e) {
print("end ["+e+"]");
});1秒ずつまちながら 5 回ループする (0,1,2,3,4)
最後の値を次へ渡したいので条件をいれてる。end [4] と最後にでる。
ぼくはわからないことがあるとすぐ日記に書こうとする。「だれかおしえてくれないかなー」と思う。でもそれと同時に、この程度がわからないと思われるのは悔やしいと思う。なので日記を書いている途中で、調べに戻って、解決したりする。最初に「これがわからない」と書いてから、ins 要素を書くまではかなり必死に集中する (誰かが教えてもらうまえに「わかった!」と書きたい)。もちろん結局わからないこともあるけど、日記に書こうとすることで、回転の悪い頭を最大限回すことができる。ついでに「何がわからないか」を文章にすることで明確にできて、書きているうちに普通に解決してしまう場合もある。だから、「わからない」と書いたはいいけど、日記として残らず消えていった文章もある。
p({ foo: "abc", bar: "def" })こうかけるやつなんだけど、JS みたいなノリで
p({ foo : "abc", bar : "def" })と書くとパースエラーになる。
シンボルキーと他のキーは同時に書けるけど、ちょっと混乱するかもしれない
p({ foo: "abc", bar: "def", "baaa" => "aaa" })それに、うえのように書いても "baaa" と :baaa は違うオブジェクトなので
p foo[:baaa] #=> nil p foo["baaa"] #=> "aaa"
self == -> { self }.()(もちろんまちがってないけど) true だしなぁ。
引数かえられないけど redo で現在のメソッドを最初からやりなおすのはできる……
Binding#callee とか実装できないかなぁ (実行中の Method/Proc をかえす)
フィルタの適用方法を変えて、importNode されたノード個々に対してフィルタを適用するようにした。本家と挙動が違うかもしれない。(フィルタ書いたことなくてよくわからない)
でもってはてなスターがロードされているページではデフォでスターをロードするようにした。Hatena.Star に特定ノード以下に制限してロードするのがあったのでそれつかってみた。(はてダのクイックページャのソースからたどった)
直書きだと、バージョンアップするたびにコピペが発生してめんどい。どうにかしたい。
MochiKit の Deferred がよくできてるなぁと実感する。Deferred チェイン中に Deferred return するとチェイン中断して……みたいなのがかっこいい (そういうのを Deferred 一個で統一してできるようにしているので MochiKit Deferred は結構サイズが大きい)。でも API がどうしても好きになれない。jQuery に移植したい。
でも慣れないとよくわからないよなぁ……(setTimeout の挙動 (ブラウザの実行キューのほげほげ) とかをわかってないと、Deferred つくってるところで setTimeout(, 0) してて、なにこれ? っておもうことになる。)
MochiKit の実装はもっとシンプルにできそうなのでつくってみた。でもいろいろ頭悪くて考えきれてないと思う……
例えばこういう風に書けるようにする。
wait(1).
next(function (e) {
log([1, e]);
return wait(1).next(function (e) {
log([2, e]);
return wait(2).next(function (e) {
log([3, e]);
});
});
}).
next(function (e) {
log(4);
return "555";
}).
next(function (e) {
log(e);
})末尾再帰っぽいの (return call ってのが tailcall っぽくてよくないですか><)
next(function () {
log("start");
}).
next(function () {
function pow (x, n) {
function _pow (n, r) {
if (n == 0) return r;
return call(_pow, n - 1, x * r);
}
return call(_pow, n, 1);
}
return call(pow, 2, 10);
}).
next(function (r) {
log([r, "end"]);
}).
error(function (e) {
alert(e);
})実装
function Deferred () { this.init.apply(this) }
Deferred.prototype = {
init : function () {
this.callback = {
ok: function (x) { return x },
ng: function (x) { throw x }
};
this._next = null;
},
next : function (fun) { return this._post("ok", fun); },
error : function (fun) { return this._post("ng", fun); },
call : function (val) { return this._fire("ok", val); },
fail : function (err) { return this._fire("ng", err); },
cancel : function () {
this._next = null;
},
_post : function (okng, fun) {
this.callback[okng] = fun;
this._next = new Deferred();
return this._next;
},
_fire : function (okng, value) {
var self = this;
var next = "ok";
try {
value = self.callback[okng].call(self, value);
} catch (e) {
next = "ng";
value = e;
}
if (value instanceof Deferred) {
value._next = self._next;
} else {
setTimeout(function () {
if (self._next) self._next._fire(next, value);
}, 0);
}
}
};
function wait(n) {
var d = new Deferred();
var t = new Date();
setTimeout(function () {
// 実際にかかった時間をコールバック
d.call((new Date).getTime() - t.getTime());
}, n * 1000)
return d;
}
function ps () {
var d = new Deferred();
setTimeout(function () { d.call() }, 0);
return d;
}
function next (fun) {
return ps().next(fun);
}
function call (f, args) {
args = Array.prototype.slice.call(arguments);
f = args.shift();
return next(function () {
return f.apply(null, args);
});
}なかなかカッコいい感じがする。もうちょいいじる。
next は this ではなくて、次の Deferred (this が準備できたらよばれる Deferred // _next) をかえす。これでずっとチェインしていく。もしコールバックが Deferred をかえしたら、その Deferred に _next をわたしてあげる。_next は継続 (ていっていいのかな。継続をちゃんと理解していない)
スタック消耗してたのを修正した
function loop (o, fun) {
var begin = o.begin || 0;
var end = o.end;
var step = o.step || 1;
var ret;
return next(function () {
function _loop (i) {
if (i < end) {
ret = fun.call(this, i, step);
return call(_loop, i + step);
} else {
return ret;
}
}
return call(_loop, begin);
});
}
next(function () {
var hoge = 0;
return loop({end:50000, step:50}, function (n, step) {
for (var i = 0; i < step; i++) {
hoge += n+i;
}
return hoge;
});
}).
next(function (e) {
log(e);
log("end");
}).
error(function (e) {
});50000回のループを50ずつ実行する。
なんかこう、ずっとひっかかってたけど、門田氏とRitaさんが微妙に唄いかたが似てることに気付いた。黄金の鐘聴いてて思った。
function Process () {
this.init.apply(this);
}
Process.prototype = {
init: function () {
var self = this;
this.stack = [];
this.rvalue = undefined;
setTimeout(function () { self.call() }, 0);
},
p: function (f) {
this.stack.unshift(f);
return this;
},
call: function () {
var self = this;
var f = this.stack.pop();
var thisObj = {};
thisObj.call = function (f, args) {
args = Array.prototype.slice.call(arguments);
f = args.shift();
self.stack.push(function () {
return f.apply(thisObj, args);
});
return "this";
};
this._rvalue = f.call(thisObj, this._rvalue);
if (this.stack.length) {
setTimeout(function () { self.call() }, 0);
}
}
};
window.onload = function () {
var ps = new Process();
ps.p(function () {
$("#content").append("<div>start!</div>");
}).p(function () {
function pow (x, n) {
function _pow (n, r) {
$("#content").append("<div>"+[n, r]+"</div>");
if (n == 0) return r;
return this.call(_pow, n - 1, x * r);
};
return this.call(_pow, n, 1);
}
return this.call(pow, 2, 1000);
}).p(function (r) {
$("#content").append("<div>end!"+r+"</div>");
});
};nemui
なんかくせになってきた。これすごい好きだ。「捨てたものを~」のところが鳥肌たつぐらい好きだ。
CD はずすと曲目と一緒に年号(のような4桁の数字)が書いてあるけど、これなんだろう。
きのうもだったけど……