Merge pull request #377 from minodisk/master

Add JSDeferred
This commit is contained in:
Diullei Gomes 2013-03-07 03:23:24 -08:00
commit f2ac28a0bd
3 changed files with 957 additions and 0 deletions

View File

@ -92,6 +92,7 @@ List of Definitions
* [jQuery.Transit](http://ricostacruz.com/jquery.transit/) (by [MrBigDog2U](https://github.com/MrBigDog2U))
* [jQuery.Validation](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) (by [Boris Yankov](https://github.com/borisyankov))
* [jQuery.Watermark](http://jquery-watermark.googlecode.com) (by [Anwar Javed](https://github.com/anwarjaved))
* [JSDeferred](http://cho45.stfuawsc.com/jsdeferred/) (by [Daisuke Mino](https://github.com/minodisk))
* [JSONEditorOnline](https://github.com/josdejong/jsoneditoronline) (by [Vincent Bortone](https://github.com/vbortone/))
* [KeyboardJS](https://github.com/RobertWHurst/KeyboardJS) (by [Vincent Bortone](https://github.com/vbortone/))
* [Knockback](http://kmalakoff.github.com/knockback/) (by [Marcel Binot](https://github.com/docgit))

View File

@ -0,0 +1,858 @@
/// <reference path="../jquery/jquery.d.ts"/>
/// <reference path="jsdeferred.d.ts"/>
declare function alert(a:any):void;
declare function log(a:any):void;
interface DeferredizedJQueryStatic extends JQueryStatic {
get(url:string, data?:any, success?:any, dataType?:any): Deferred;
}
declare var $: DeferredizedJQueryStatic;
declare interface http {
get(url:string):Deferred;
}
/***** jsDoc case *****/
// constructor
(()=> {
var d = new Deferred();
var d = Deferred();
})();
// define
(()=> {
Deferred.define();
$.get("/hoge").next(function (data) {
alert(data);
}).
parallel([$.get("foo.html"), $.get("bar.html")]).next(function (values) {
log($.map(values, function (v) { return v.length }));
if (values[1].match(/nextUrl:\s*(\S+)/)) {
return $.get(RegExp.$1).next(function (d) {
return d;
});
}
}).
next(function (d) {
log(d.length);
});
})();
// next
(()=> {
var d = new Deferred();
d.
next(function () {
alert(1);
}).
next(function () {
alert(2);
});
d.call();
})();
// error
(()=> {
var d = new Deferred();
d.
next(function () {
alert(1);
throw "foo";
}).
next(function () {
alert('not shown');
}).
error(function (e) {
alert(e); //=> "foo"
});
d.call();
})();
// call
(()=> {
var d = new Deferred();
setTimeout(function () {
d.call('value');
}, 100);
return d;
})();
// fail
(()=> {
var d = new Deferred();
var x = new XMLHttpRequest();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) d.call(x); else d.fail(x);
}
};
return d;
})();
// chain
(()=> {
chain(
function () {
return wait(0.5);
},
function (w) {
throw "foo";
},
function error(e) {
alert(e);
},
[
function () {
return wait(1);
},
function () {
return wait(2);
}
],
function (result) {
alert([ result[0], result[1] ]);
},
{
foo: wait(1),
bar: wait(1)
},
function (result) {
alert([ result.foo, result.bar ]);
},
function error(e) {
alert(e);
}
);
})();
// wait
(()=> {
wait(1).next(function (elapsed) {
log(elapsed); //=> may be 990-1100
});
})();
// call
(()=> {
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"]);
});
})();
// parallel
(()=> {
parallel([
$.get("foo.html"),
$.get("bar.html")
]).next(function (values) {
values[0] //=> foo.html data
values[1] //=> bar.html data
});
parallel({
foo: $.get("foo.html"),
bar: $.get("bar.html")
}).next(function (values) {
values.foo //=> foo.html data
values.bar //=> bar.html data
});
})();
// loop
(()=> {
//=> loop 1 to 100
loop({begin: 1, end: 100, step: 10}, function (n, o) {
for (var i = 0; i < o.step; i++) {
log(n + i);
}
});
//=> loop 10 times with sleeping 1 sec in each loop.
loop(10, function (n) {
log(n);
return wait(1);
});
})();
// repeat
(()=> {
repeat(10, function (i) {
i //=> 0,1,2,3,4,5,6,7,8,9
});
})();
// register
(()=> {
// Deferred.register("loop", loop);
// Global Deferred function
loop(10,function (n) {
print(n);
}).
// Registered Deferred.prototype.loop
loop(10, function (n) {
print(n);
});
})();
// connect
(()=> {
var timeout = Deferred.connect(setTimeout, { target: window, ok: 0 });
timeout(1).next(function () {
alert('after 1 sec');
});
var timeout = Deferred.connect(window, "setTimeout");
timeout(1).next(function () {
alert('after 1 sec');
});
})();
// retry
(()=> {
Deferred.retry(3,function () {
return http.get('foo.html');
}).
next(function (res) {
res //=> response if succeeded
}).
error(function (e) {
e //=> error if all try failed
});
})();
/***** Tutorial case *****/
(()=> {
Deferred.define();
next(function () {
alert("Hello!");
return wait(5);
}).
next(function () {
alert("World!");
});
Deferred.next(function () {
alert("Hello!");
return Deferred.wait(5);
}).
next(function () {
alert("World!");
});
// http.get is assumed to be a function that takes a URI as an argument and returns a Deferred instance
var results = [];
next(function () {
return http.get("/foo.json").next(function (data) {
results.push(data);
});
}).
next(function () {
return http.get("/baz.json").next(function (data) {
results.push(data);
});
}).
next(function () {
return http.get("/baz.json").next(function (data) {
results.push(data);
});
}).
next(function () {
alert(results);
});
var wants = ["/foo.json", "/bar.json", "/baz.json"];
var results = [];
loop(wants.length,function (i) {
return http.get(wants[i]).next(function (data) {
results.push(data);
});
}).
next(function () {
alert(results);
});
parallel([
http.get("/foo.json"),
http.get("/bar.json"),
http.get("/baz.json")
]).
next(function (results) {
alert(results);
});
next(function () {
// something 1
}).
next(function () {
// asynchronous process
throw "error!";
}).
next(function () {
// something 2 (not executed as an error occurs in the previous process)
});
next(function () {
// something 1
}).
next(function () {
// asynchronous process
throw "error!";
}).
next(function () {
// something 2 (not executed as an error occurs in the previous process)
}).
error(function (e) {
alert(e);
});
next(function () {
// something 1
}).
next(function () {
// asynchronous process
throw "error!";
}).
error(function (e) {
alert(e);
}).
next(function () {
// something 2 (executed since the exception would already be handled)
}).
error(function (e) {
alert(e);
});
next(function () {
alert("Hello!");
return wait(5);
}).
next(function () {
alert("World!");
});
next(function () {
alert(1);
return next(function () {
alert(2);
}).
next(function () {
alert(3);
});
}).
next(function () {
alert(4);
});
var http = {}
http.get = function (uri) {
var deferred = new Deferred();
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
deferred.call(xhr);
} else {
deferred.fail(xhr);
}
}
};
deferred.canceller = function () { xhr.abort() };
return deferred;
}
loop(1000, function (n) {
// heavy process
});
function repeat(n, f) {
var i = 0, end = {}, ret = null;
return Deferred.next(function () {
var t = (new Date()).getTime();
divide: {
do {
if (i >= n) break divide;
ret = f(i++);
} while ((new Date()).getTime() - t < 20);
return Deferred.call(arguments.callee);
}
});
}
next(function () {
console.log("start");
}).
next(function () {
function pow(x, n) {
function _pow(n, r) {
console.log([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) {
console.log([r, "end"]);
}).
error(function (e) {
alert(e);
})
loop(10, function (i) {
console.log(i)
});
$.get("README.markdown").next(function (data) {
console.log(data);
});
})();
(()=> {
console.log("start. gathering data.");
parallel([$.get("README.markdown"), $.get("ChangeLog")]).
next(function (values) {
var lengths = $.map(values, function (i) { return i.length });
console.log(lengths.join(", "));
});
})();
(()=> {
console.log("start. gathering data.");
parallel({html: $.get("README.markdown"), js: $.get("ChangeLog")}).
next(function (values) {
console.log(["html=", values.html.length, " js=", values.js.length].join(""));
});
})();
(()=> {
console.log("start. wait 3 sec.");
var list = [];
var printAndReturn = function (i) {
console.log(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) {
console.log("Completed. values: " + values.join(", "));
});
})();
(()=> {
var queue = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var workers = new Array(2);
var work = function (job) {
console.log('working... ' + job);
return wait(Math.random() * 4);
};
for (var i = 0, len = workers.length; i < len; i++) {
workers[i] = next(function me() {
var job = queue.shift();
if (!job) return;
console.log("start worker: " + job);
return next(function () { return job }).
next(work).
next(me);
}).
error(function (e) {
alert(e);
});
}
parallel(workers).next(function () {
console.log('all done!');
});
})();
(()=> {
next(function () {
var sum = 0;
return loop({end: 100000, step: 1000}, function (n, o) {
console.log(["Processing divided loop:n=", n, ", sum=", sum, " last?=", o.last].join(""));
for (var i = 0; i < o.step; i++) {
// console.log(i + n);
sum += i + n;
}
console.log(["sum=", sum].join(""));
return sum;
});
}).
next(function (e) {
console.log("Result:" + e);
console.log("end");
}).
error(function (e) {
console.log(e);
});
})();
(()=> {
loop({begin: 1, end: 100, step: 10}, function (n, o) {
console.log(["Processing divided loop:n=", n, " last?=", o.last].join(""));
for (var i = 0; i < o.step; i++) {
var j = n + i;
console.log(j);
}
});
})();
(()=> {
Deferred.repeat(100, function (n, o) {
console.log(n);
for (var i = 0; i < Math.pow(n, 2); i++) {
for (var j = n; j; j--);
}
});
})();
(()=> {
loop(10, function (n) {
console.log(n);
return wait(0.1);
});
loop(10, function (n) {
console.log(String.fromCharCode(97 + n));
return wait(0.2);
});
})();
(()=> {
console.log(0);
loop(10,function (n) {
console.log(n);
return n;
}).
wait(1).
loop(10,function (n) {
var c = String.fromCharCode(97 + n);
console.log(c);
return c;
}).
next(function (i) {
console.log("end");
}).
error(function (e) {
alert(e);
});
})();
(()=> {
loop(5,function (i, o) {
console.log(i);
return o.last ? i : wait(1);
}).
next(function (e) {
console.log("end [" + e + "]");
}).
error(function (e) {
console.log(e);
});
})();
(()=> {
next(function (i) {
function delayloop(i) {
console.log(i++);
if (i < 5) {
return wait(1).next(function () {
return call(delayloop, i);
});
}
}
return call(delayloop, 0);
}).
next(function (e) {
console.log("end");
}).
error(function (e) {
console.log(e);
});
})();
(()=> {
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) {
console.log("callcc1 returns:" + val);
});
// should show "callcc1 returns:20"
var cont;
var i = 0;
callcc(function (c) {
cont = c;
return 10;
}).
next(function (val) {
console.log("callcc2 returns:" + val);
if (!i++) cont(20);
});
// should show "callcc2 returns:10", "callcc returns:20"
})();
(()=> {
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
// Just port above.
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) {
console.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) {
console.log(vars);
// 簡易 distinct
assert([baker, cooper, fletcher, miller, smith].uniq().length == 5);
console.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) {
console.log("solved");
console.log(vars);
alert(uneval(vars));
}
}).
error(function (e) {
alert(e)
});
})();
(()=> {
var d1 = new Deferred();
d1.callback.ok = function () {
alert("1");
};
var d2 = new Deferred();
d2.callback.ok = function () {
alert("2");
};
// Set d2 as continuation of d1.
d1._next = d2;
// Invoke the chain.
d1.call();
})();
(()=> {
next(function () { // this `next` is global function
alert("1");
}).
next(function () { // this `next` is Deferred#next
alert("2");
}).
next(function () {
alert("3");
});
})();
(()=> {
next(function () {
alert("1");
}).
next(function () {
alert("2");
// child Deferred
return next(function () {
alert("3");
});
}).
next(function () {
alert("4");
});
})();
(()=> {
next(function () {
alert("1");
}).
next(function () {
alert("2");
var d = next(function () {
alert("3");
});
d._next = this._next;
this.cancel();
}).
next(function () {
alert("4");
});
})();
(()=> {
next(function () {
alert("1");
}).
next(function () {
alert("2");
next(function () {
alert("3");
}).
next(function () {
alert("4");
});
});
})();
(()=> {
next(function () {
throw "Error";
}).
error(function (e) {
expect("Errorback called", "Error", e);
return e; // recovering error
}).
next(function (e) {
expect("Callback called", "Error", e);
throw "Error2";
}).
next(function (e) {
// This process is not called because
// the error is not recovered.
ng("Must not be called!!");
}).
error(function (e) {
expect("Errorback called", "Error2", e);
});
})();

98
jsdeferred/jsdeferred.d.ts vendored Normal file
View File

@ -0,0 +1,98 @@
// Type definitions for JSDeferred
// Project: https://github.com/cho45/jsdeferred
// Definitions by: Daisuke Mino <https://github.com/minodisk>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
interface Loop {
begin:number;
end:number;
step:number;
}
interface ConnectOption {
target:any;
args?:any[];
ok?:number;
ng?:number;
}
interface RetryOption {
wait:number;
}
interface DeferredizedFunction { (...arg:any[]):Deferred; }
interface DeferredizedFunctionWithNumber { (n:number):Deferred; }
interface FunctionWithNumber { (i:number); }
interface ErrorCallback { (d:Deferred, ...args:any[]); }
declare class Deferred {
static methods:string[];
static isDeferred(obj:any):bool;
static next(fun:Function):Deferred;
static chain(...args:any[]):Deferred;
static wait(n:number):Deferred;
static call(fun?:Function, ...args:any[]):Deferred;
static parallel(dl:any):Deferred;
static earlier(dl:any):Deferred;
static loop(n:number, fun:FunctionWithNumber):Deferred;
static loop(n:Loop, fun:FunctionWithNumber):Deferred;
static repeat(n:number, fun:FunctionWithNumber):Deferred;
static register(name:string, fun:DeferredizedFunction):void;
static connect(funo:any, options:string):DeferredizedFunction;
static connect(funo:Function, options?:ConnectOption):DeferredizedFunction;
static retry(retryCount:number, funcDeferred:DeferredizedFunctionWithNumber, options?:RetryOption):Deferred;
static define(obj?:any, list?:string[]):any;
constructor();
next(fun:Function):Deferred;
wait(n:number):Deferred;
error(fun:ErrorCallback):Deferred;
call(val?:any):Deferred;
fail(err:any):Deferred;
cancel():Deferred;
parallel(dl:any):Deferred;
loop(n:number, fun:FunctionWithNumber):Deferred;
loop(n:Loop, fun:FunctionWithNumber):Deferred;
}
declare function chain(...args:any[]):Deferred;
declare function wait(n:number):Deferred;
declare function call(fun?:Function, ...args:any[]):Deferred;
declare function parallel(dl:any):Deferred;
declare function earlier(dl:any):Deferred;
declare function loop(n:number, fun:FunctionWithNumber):Deferred;
declare function loop(n:Loop, fun:FunctionWithNumber):Deferred;
declare function repeat(n:number, fun:FunctionWithNumber):Deferred;