Export deferred functions.
// export functions to global; Deferred.define(); // export to aObj // Deferred.define(aObj); // export specic functions // var global = (function () { return this })(); // Deferred.define(global, ["next"]); // full name Deferred.next(fun);
Basic Chain
next(function () { print("start"); }). next(function () { function pow (x, n) { function _pow (n, r) { print([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) { print([r, "end"]); }). error(function (e) { alert(e); }) function print (m) { $("#basic-code").append("\n// "+m) }
Basic Loop
This loop is slow but not blocking browsing.
loop(10, function (i) { print(i) }); function print (m) { $("#basic-loop-code").append("\n// "+m) }
Deferred Ajax
$.get("sample.html").next(function (data) { $("#ajax-code").append("\n// "+data.length); });
Parallel Deferred
DeferredList
print("start. gathering data."); parallel([$.get("sample.html"), $.get("jsdeferred.js")]). next(function (values) { var lengths = $.map(values, function (i) { return i.length }); print(lengths.join(", ")); }); function print (m) { $("#parallel-code").append("\n// "+m) }
print("start. gathering data."); // named parallel deferred parallel({html: $.get("sample.html"), js: $.get("jsdeferred.js")}). next(function (values) { print(["html=", values.html.length, " js=", values.js.length].join("")); }); function print (m) { $("#parallel-code2").append("\n// "+m) }
print("start. wait 3 sec."); var list = []; var printAndReturn = function (i) { print(i+"msec elapsed"); return i; }; list.push(wait(0).next(printAndReturn)); list.push(wait(1).next(printAndReturn)); list.push(wait(2).next(printAndReturn)); list.push(wait(3).next(printAndReturn)); parallel(list).next(function (values) { print("Completed. values: "+values.join(", ")); }); function print (m) { $("#parallel-code1").append("\n// "+m) }
Workers
var queue = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var workers = new Array(2); var work = function (job) { print('working... ' + job); return wait(3); }; for (var i = 0, len = workers.length; i < len; i++) { workers[i] = next(function me () { var job = queue.shift(); if (!job) return; print("start worker: " + job); return next(function () { return job }). next(work). next(me); }). error(function (e) { alert(e); }); } parallel(workers).next(function () { print('all done!'); }); function print (m) { $("#worker-code").append("\n// "+m) }
Divided Loop
next(function () { var sum = 0; return loop({end:100000, step:1000}, function (n, o) { print(["Processing divided loop:n=", n, ", sum=", sum, " last?=", o.last].join("")); for (var i = 0; i < o.step; i++) { // print(i + n); sum += i + n; } print(["sum=", sum].join("")); return sum; }); }). next(function (e) { print("Result:"+e); print("end"); }). error(function (e) { print(e); }); function print (m) { $("#loop-code").append("\n// "+m) }
loop({begin: 1, end:100, step:10}, function (n, o) { print(["Processing divided loop:n=", n, " last?=", o.last].join("")); for (var i = 0; i < o.step; i++) { var j = n + i; print(j); } }); function print (m) { $("#loop-code1").append("\n// "+m) }
Auto Divided Loop
function aloop (n, f) { var i = 0; var end = new Object; var ret = null; return Deferred.next(function () { var t = (new Date()).getTime(); try { do { ret = f(i) i++; if (i >= n) throw end; } while ((new Date()).getTime() - t < 50); print("Devided: " + ((new Date()).getTime() - t) + "msec."); return Deferred.call(arguments.callee); } catch (e) { if (e == end) { print("End"); return ret; } else { throw e; } } }); } aloop(100, function (n, o) { print(n); for (var i = 0; i < Math.pow(n, 2); i++) { for (var j = n; j; j--); } }); function print (m) { $("#aloop-code").append("\n// "+m) }
Pseudo Multi Thread
loop(10, function (n) { print(n); return wait(0.1); }); loop(10, function (n) { print(String.fromCharCode(97+n)); return wait(0.2); }); function print (m) { $("#thread-code").append(" "+m) } //
Shorthand
print(0); loop(10, function (n) { print(n); return n; }). wait(1). loop(10, function (n) { var c = String.fromCharCode(97+n); print(c); return c; }). next(function (i) { print("end"); }). error(function (e) { alert(e); }); function print (m) { $("#shorthand-code").append(" "+m) } //
Tiny Effects
function effect (o) { var start = new Date().valueOf(); var curr = +o.target.style[o.name].match(/\d+/); return next(function () { var rate = (new Date().valueOf() - start) / o.time; if (rate > 1) rate = 1; o.target.style[o.name] = (curr + rate * o.value) + "px"; if (rate < 1) { return call(arguments.callee); } }); } // register function to use shorthand of chain $.deferred.register("effect", effect); var ele = document.getElementById("effect-code1"); effect({ target : ele, name : "left", value : 100, time : 300 }). effect({ target : ele, name : "top", value : 100, time : 300 }). next(function () { return parallel([ effect({ target : ele, name : "left", value : -100, time : 300 }), effect({ target : ele, name : "top", value : -100, time : 300 }) ]); }). error(function (e) { alert(e); });
Delay Loop
loop(5, function (i, o) { print(i); return o.last? i : wait(1); }). next(function (e) { print("end ["+e+"]"); }). error(function (e) { print(e); }); function print (m) { $("#delay-loop-code1").append("\n// "+m) }
next(function (i) { function delayloop (i) { print(i++); if (i < 5) { return wait(1).next(function () { return call(delayloop, i); }); } } return call(delayloop, 0); }). next(function (e) { print("end"); }). error(function (e) { print(e); }); function print (m) { $("#delay-loop-code").append("\n// "+m) }
Step Run (event handling)
(double click to run this code and click to step)
var deferred = Deferred(); $("#step-run").click(function () { deferred.call() }); loop(5, function (i) { print("running... " + i); return deferred; }). next(function () { print("completed"); }); function print (m) { $("#step-run").append("\n// "+m) }
Brainfuck interpreter
No wait but toooooooo slow :( But, but, browser will not be stopped!
function bfrun () { var mem = $("<pre/>"), out = $("<pre/>"), button = $("#bfi-run").hide(); var sinput = $("#bfi-source").hide(), source = sinput.val(); var shtml = $("<div class='code'/>"); var selems = $.map(source.split(/\n/), function (l) { var line = $("<div class='line'/>").appendTo(shtml); return $.map(l.split(""), function (c) { return $("<span/>").append(c).appendTo(line); }) }); sinput.before(mem).before(out).before(shtml); var pi = { "+": function (c) { if (!c.stack[0]) return c; c.memory[c.pointer]++; return c; }, "-": function (c) { if (!c.stack[0]) return c; c.memory[c.pointer]--; return c; }, ">": function (c) { if (!c.stack[0]) return c; c.pointer++; c.memory[c.pointer] = (c.memory[c.pointer] || 0); return c; }, "<": function (c) { if (!c.stack[0]) return c; c.pointer--; c.memory[c.pointer] = (c.memory[c.pointer] || 0); return c; }, ".": function (c) { if (!c.stack[0]) return c; c.output.push(String.fromCharCode(c.memory[c.pointer])); return c; }, ",": function (c) { if (!c.stack[0]) return c; c.memory[c.pointer] = "t"; return c; }, "[": function (c) { if (c.memory[c.pointer] == 0) { c.stack.unshift(false); } else { c.stack.unshift(c.pos - 1); } return c; }, "]": function (c) { var s = c.stack.shift(); if (s) c.pos = s; return c; } }; next(function () { return { pos : 0, pointer : 0, memory : [0], stack : [true], output : [], source : source }; }). next(function (c) { if (selems[c.pos]) selems[c.pos].removeClass("em"); var chr, fun; do { chr = c.source.charAt(c.pos); fun = pi[chr]; c.pos++; } while (chr.match(/[^<>,.\[\]+-]/)); var m = c.memory.concat(); m.splice(c.pointer, 1, "*"+(c.memory[c.pointer] || 0)); mem.text(m.join(", ")); out.text(c.output.join("")); if (typeof fun == "function") { c = fun(c); if (c.pos < c.source.length) { if (selems[c.pos]) selems[c.pos].addClass("em"); return call(arguments.callee, c); } else { return c; } } else { return c; } }). next(function (c) { var reset = $("<button>Reset</button>") sinput.after(reset); reset.click(function () { sinput.show(); button.show(); mem.remove(); out.remove(); shtml.remove(); reset.remove(); }); log("end"); }). error(function (e) { alert(e); }); function log (m) { // console.log(uneval(m)); } }
callcc
like Scheme's callcc
function callcc (fun) { var error = new Deferred(); return call(function () { // JSDeferred passes current Deferred Object to this. var ccdeferred = this; // Call with current continuation (calling Deferred.next) return fun(function (a) { ccdeferred._next.call(a); throw error }); }). error(function (e) { // Current Deferred chain must be stopped if (e === error) { return e; } else { throw e; } }); } callcc(function (cont) { return 10 * 10 * cont(20); }). next(function (val) { print("callcc1 returns:" + val); }); // should show "callcc1 returns:20" var cont; var i = 0; callcc(function (c) { cont = c; return 10; }). next(function (val) { print("callcc2 returns:" + val); if (!i++) cont(20); }); // should show "callcc2 returns:10", "callcc returns:20" function print (m) { $("#callcc").append("\n// "+m) }
and Scheme's amb
function callcc (fun) { var error = new Deferred(); return call(function () { // JSDeferred passes current Deferred Object to this. var ccdeferred = this; // Call with current continuation (calling Deferred.next) return fun(function (a) { ccdeferred._next.call(a); throw error }); }). error(function (e) { // Current Deferred chain must be stopped if (e === error) { return e; } else { throw e; } }); } // http://www.sampou.org/scheme/t-y-scheme/t-y-scheme-Z-H-16.html#node_chap_14 // 上記のものをそのまま移植したもの function amb () { var alts = arguments; var prevAmbFail = amb.ambFail; return callcc(function (sk) { return loop(alts.length, function (i) { var alt = alts[i]; return callcc(function (fk) { amb.ambFail = function () { amb.ambFail = prevAmbFail; return fk("fail"); }; return sk(alt); }); }). next(prevAmbFail); }); } amb.ambFail = function () { throw "amb tree exhausted" }; // Utility function function amb1 (ambvars) { var f = wait(0); var vars = {}; for (var k in ambvars) if (ambvars.hasOwnProperty(k)) (function (name, val) { log(name); f = f.next(function () { return amb.apply(this, val).next(function (i) { vars[name] = i; return vars; }); }); })(k, ambvars[k]); return f; } function assert (cond) { if (!cond) throw amb(); } // http://mayokara.info/note/view/251 Array.prototype.uniq = function(){ for (var i = 0,l = this.length; i < l; i++) { if (this.indexOf(this[i]) < i) { this.splice(i--, l-- && 1); } } return this; }; amb1({ baker : [1, 2, 3, 4, 5], cooper : [1, 2, 3, 4, 5], fletcher : [1, 2, 3, 4, 5], miller : [1, 2, 3, 4, 5], smith : [1, 2, 3, 4, 5] }). next(function (vars) { with (vars) { log(vars); // 簡易 distinct assert([baker, cooper, fletcher, miller, smith].uniq().length == 5); log("distinct passed"); assert(baker != 5); assert(cooper != 1); assert(fletcher != 1 && fletcher != 5); assert(miller > cooper); assert(Math.abs(smith - fletcher) != 1); assert(Math.abs(fletcher - cooper) != 1); return vars; } }). next(function (vars) { with (vars) { log("solved"); log(vars); alert(uneval(vars)); } }). error(function (e) { alert(e) }); function log (m) { $("#amb").append("\n// "+ uneval(m)) }