update jsdeferred
This commit is contained in:
parent
039e188469
commit
41eb5685b2
@ -1,101 +1,28 @@
|
||||
// Usage:: Components.utils.import('..../jsdeferred.jscodemodule.js');
|
||||
// JSDeferred 0.3.4 Copyright (c) 2007 cho45 ( www.lowreal.net )
|
||||
// See http://github.com/cho45/jsdeferred
|
||||
var EXPORTED_SYMBOLS = ['Deferred'];
|
||||
var window = {};
|
||||
var location = { protocol: 'resource:' };
|
||||
var document = { addEventListener : function() {} };
|
||||
|
||||
Components.utils.import('resource://treestyletab-modules/lib/jstimer.jsm', window);
|
||||
var setTimeout = window.setTimeout;
|
||||
var clearTimeout = window.clearTimeout;
|
||||
var setInterval = window.setInterval;
|
||||
var clearInterval = window.clearInterval;
|
||||
function setTimeout(aCallback, aDelay) {
|
||||
var timer = Components.classes['@mozilla.org/timer;1']
|
||||
.createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback(aCallback, aDelay, timer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
}
|
||||
|
||||
function clearTimeout(aTimer) {
|
||||
aTimer.cancel();
|
||||
}
|
||||
|
||||
|
||||
/* Header::
|
||||
* JSDeferred
|
||||
* Copyright (c) 2007 cho45 ( www.lowreal.net )
|
||||
*
|
||||
* http://coderepos.org/share/wiki/JSDeferred
|
||||
*
|
||||
* Version:: 0.3.0
|
||||
* License:: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
/* Usage (with jQuery)::
|
||||
*
|
||||
* $.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);
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* function Deferred () //=> constructor
|
||||
*
|
||||
* `Deferred` function is constructor of Deferred.
|
||||
*
|
||||
* Sample:
|
||||
* var d = new Deferred();
|
||||
* // or this is shothand of above.
|
||||
* var d = Deferred();
|
||||
*/
|
||||
/* function Deferred.prototype.next (fun) //=> Deferred
|
||||
*
|
||||
* Create new Deferred and sets `fun` as its callback.
|
||||
*/
|
||||
/* function Deferred.prototype.error (fun) //=> Deferred
|
||||
*
|
||||
* Create new Deferred and sets `fun` as its errorback.
|
||||
*
|
||||
* If `fun` not throws error but returns normal value, Deferred treats
|
||||
* the given error is recovery and continue callback chain.
|
||||
*/
|
||||
/* function Deferred.prototype.call (val) //=> this
|
||||
*
|
||||
* Invokes self callback chain.
|
||||
*/
|
||||
/* function Deferred.prototype.fail (err) //=> this
|
||||
*
|
||||
* Invokes self errorback chain.
|
||||
*/
|
||||
/* function Deferred.prototype.cancel (err) //=> this
|
||||
*
|
||||
* Cancels self callback chain.
|
||||
*/
|
||||
function Deferred () { return (this instanceof Deferred) ? this.init() : new Deferred() }
|
||||
Deferred.ok = function (x) { return x };
|
||||
Deferred.ng = function (x) { throw x };
|
||||
Deferred.prototype = {
|
||||
|
||||
init : function () {
|
||||
this._next = null;
|
||||
this.callback = {
|
||||
@ -105,11 +32,19 @@ Deferred.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
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.canceller || function () {})();
|
||||
return this.init();
|
||||
@ -139,11 +74,6 @@ Deferred.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/* function next (fun) //=> Deferred
|
||||
*
|
||||
* `next` is shorthand for creating new deferred which
|
||||
* is called after current queue.
|
||||
*/
|
||||
Deferred.next_default = function (fun) {
|
||||
var d = new Deferred();
|
||||
var id = setTimeout(function () { d.call() }, 0);
|
||||
@ -151,15 +81,14 @@ Deferred.next_default = function (fun) {
|
||||
if (fun) d.callback.ok = fun;
|
||||
return d;
|
||||
};
|
||||
Deferred.next_faster_way_readystatechange = ((location.protocol == "http:") && !window.opera && /\bMSIE\b/.test(navigator.userAgent)) && function (fun) {
|
||||
// MSIE
|
||||
Deferred.next_faster_way_readystatechange = ((typeof window === 'object') && (location.protocol == "http:") && !window.opera && /\bMSIE\b/.test(navigator.userAgent)) && function (fun) {
|
||||
var d = new Deferred();
|
||||
var t = new Date().getTime();
|
||||
if (t - arguments.callee._prev_timeout_called < 150) {
|
||||
var cancel = false;
|
||||
var script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
script.src = "javascript:";
|
||||
script.src = "data:text/javascript,";
|
||||
script.onreadystatechange = function () {
|
||||
if (!cancel) {
|
||||
d.canceller();
|
||||
@ -182,8 +111,7 @@ Deferred.next_faster_way_readystatechange = ((location.protocol == "http:") && !
|
||||
if (fun) d.callback.ok = fun;
|
||||
return d;
|
||||
};
|
||||
Deferred.next_faster_way_Image = ((typeof(Image) != "undefined") && document.addEventListener) && function (fun) {
|
||||
// Modern Browsers
|
||||
Deferred.next_faster_way_Image = ((typeof window === 'object') && (typeof(Image) != "undefined") && !window.opera && document.addEventListener) && function (fun) {
|
||||
var d = new Deferred();
|
||||
var img = new Image();
|
||||
var handler = function () {
|
||||
@ -196,24 +124,46 @@ Deferred.next_faster_way_Image = ((typeof(Image) != "undefined") && document.add
|
||||
img.removeEventListener("load", handler, false);
|
||||
img.removeEventListener("error", handler, false);
|
||||
};
|
||||
img.src = "data:,/ _ / X";
|
||||
img.src = "data:image/png," + Math.random();
|
||||
if (fun) d.callback.ok = fun;
|
||||
return d;
|
||||
};
|
||||
Deferred.next_tick = (typeof process === 'object' && typeof process.nextTick === 'function') && function (fun) {
|
||||
var d = new Deferred();
|
||||
process.nextTick(function() { d.call() });
|
||||
if (fun) d.callback.ok = fun;
|
||||
return d;
|
||||
};
|
||||
Deferred.next = Deferred.next_faster_way_readystatechange ||
|
||||
Deferred.next_faster_way_Image ||
|
||||
Deferred.next_tick ||
|
||||
Deferred.next_default;
|
||||
|
||||
/* function wait (sec) //=> Deferred
|
||||
*
|
||||
* `wait` returns deferred that will be called after `sec` elapsed
|
||||
* with real elapsed time (msec)
|
||||
*
|
||||
* Sample:
|
||||
* wait(1).next(function (elapsed) {
|
||||
* log(elapsed); //=> may be 990-1100
|
||||
* });
|
||||
*/
|
||||
Deferred.chain = function () {
|
||||
var chain = Deferred.next();
|
||||
for (var i = 0, len = arguments.length; i < len; i++) (function (obj) {
|
||||
switch (typeof obj) {
|
||||
case "function":
|
||||
var name = null;
|
||||
try {
|
||||
name = obj.toString().match(/^\s*function\s+([^\s()]+)/)[1];
|
||||
} catch (e) { }
|
||||
if (name != "error") {
|
||||
chain = chain.next(obj);
|
||||
} else {
|
||||
chain = chain.error(obj);
|
||||
}
|
||||
break;
|
||||
case "object":
|
||||
chain = chain.next(function() { return Deferred.parallel(obj) });
|
||||
break;
|
||||
default:
|
||||
throw "unknown type in process chains";
|
||||
}
|
||||
})(arguments[i]);
|
||||
return chain;
|
||||
};
|
||||
|
||||
Deferred.wait = function (n) {
|
||||
var d = new Deferred(), t = new Date();
|
||||
var id = setTimeout(function () {
|
||||
@ -223,63 +173,18 @@ Deferred.wait = function (n) {
|
||||
return d;
|
||||
};
|
||||
|
||||
/* function call (fun [, args...]) //=> Deferred
|
||||
*
|
||||
* `call` function is for calling function asynchronous.
|
||||
*
|
||||
* Sample:
|
||||
* // like tail recursion
|
||||
* 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"]);
|
||||
* });
|
||||
*
|
||||
*/
|
||||
Deferred.call = function (f /* , args... */) {
|
||||
Deferred.call = function (fun) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return Deferred.next(function () {
|
||||
return f.apply(this, args);
|
||||
return fun.apply(this, args);
|
||||
});
|
||||
};
|
||||
|
||||
/* function parallel (deferredlist) //=> Deferred
|
||||
*
|
||||
* `parallel` wraps up `deferredlist` to one deferred.
|
||||
* This is useful when some asynchronous resources required.
|
||||
*
|
||||
* `deferredlist` can be Array or Object (Hash).
|
||||
*
|
||||
* Sample:
|
||||
* 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
|
||||
* });
|
||||
*/
|
||||
Deferred.parallel = function (dl) {
|
||||
if (arguments.length > 1) dl = Array.prototype.slice.call(arguments);
|
||||
var ret = new Deferred(), values = {}, num = 0;
|
||||
for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
|
||||
if (typeof d == "function") d = Deferred.next(d);
|
||||
d.next(function (v) {
|
||||
values[i] = v;
|
||||
if (--num <= 0) {
|
||||
@ -304,12 +209,8 @@ Deferred.parallel = function (dl) {
|
||||
return ret;
|
||||
};
|
||||
|
||||
/* function earlier (deferredlist) //=> Deferred
|
||||
*
|
||||
* Continue process when one deferred in `deferredlist` has completed. Others will cancel.
|
||||
* parallel ('and' processing) <=> earlier ('or' processing)
|
||||
*/
|
||||
Deferred.earlier = function (dl) {
|
||||
if (arguments.length > 1) dl = Array.prototype.slice.call(arguments);
|
||||
var ret = new Deferred(), values = {}, num = 0;
|
||||
for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
|
||||
d.next(function (v) {
|
||||
@ -336,24 +237,6 @@ Deferred.earlier = function (dl) {
|
||||
};
|
||||
|
||||
|
||||
/* function loop (n, fun) //=> Deferred
|
||||
*
|
||||
* `loop` function provides browser-non-blocking loop.
|
||||
* This loop is slow but not stop browser's appearance.
|
||||
*
|
||||
* Sample:
|
||||
* //=> 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
|
||||
* loop(10, function (n) {
|
||||
* log(n);
|
||||
* });
|
||||
*/
|
||||
Deferred.loop = function (n, fun) {
|
||||
var o = {
|
||||
begin : n.begin || 0,
|
||||
@ -389,47 +272,21 @@ Deferred.loop = function (n, fun) {
|
||||
};
|
||||
|
||||
|
||||
/* function repeat (n, fun) //=> Deferred
|
||||
*
|
||||
* Loop `n` tiems with `fun`.
|
||||
* This function automatically return control to browser, if loop time over 20msec.
|
||||
* This is useful for huge loop not to block browser UI.
|
||||
*
|
||||
* Sample::
|
||||
* repeat(10, function (i) {
|
||||
* i //=> 0,1,2,3,4,5,6,7,8,9
|
||||
* });
|
||||
*/
|
||||
Deferred.repeat = function (n, f) {
|
||||
Deferred.repeat = function (n, fun) {
|
||||
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++);
|
||||
ret = fun(i++);
|
||||
} while ((new Date()).getTime() - t < 20);
|
||||
return Deferred.call(arguments.callee);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
/* function Deferred.register (name, fun) //=> void 0
|
||||
*
|
||||
* Register `fun` to Deferred prototype for method chain.
|
||||
*
|
||||
* Sample::
|
||||
* // Deferred.register("loop", loop);
|
||||
*
|
||||
* // Global Deferred function
|
||||
* loop(10, function (n) {
|
||||
* print(n);
|
||||
* }).
|
||||
* // Registered Deferred.prototype.loop
|
||||
* loop(10, function (n) {
|
||||
* print(n);
|
||||
* });
|
||||
*/
|
||||
Deferred.register = function (name, fun) {
|
||||
this.prototype[name] = function () {
|
||||
var a = arguments;
|
||||
@ -442,33 +299,31 @@ Deferred.register = function (name, fun) {
|
||||
Deferred.register("loop", Deferred.loop);
|
||||
Deferred.register("wait", Deferred.wait);
|
||||
|
||||
/* Deferred.connect (func [, opts: { ok : 0, ng : null, target: null} ]) //=> Function //=> Deferred
|
||||
*
|
||||
* Connect a function with Deferred. That is, transform a function
|
||||
* that takes a callback into one that returns a Deferred object.
|
||||
*
|
||||
* Sample::
|
||||
* var timeout = Deferred.connect(setTimeout, { target: window, ok: 0 });
|
||||
* timeout(1).next(function () {
|
||||
* alert('after 1 sec');
|
||||
* });
|
||||
*/
|
||||
// Allow to pass multiple values to next.
|
||||
Deferred.Arguments = function (args) { this.args = Array.prototype.slice.call(args, 0) }
|
||||
Deferred.connect = function (func, obj) {
|
||||
if (!obj) obj = {};
|
||||
var callbackArgIndex = obj.ok;
|
||||
Deferred.connect = function (funo, options) {
|
||||
var target, func, obj;
|
||||
if (typeof arguments[1] == "string") {
|
||||
target = arguments[0];
|
||||
func = target[arguments[1]];
|
||||
obj = arguments[2] || {};
|
||||
} else {
|
||||
func = arguments[0];
|
||||
obj = arguments[1] || {};
|
||||
target = obj.target;
|
||||
}
|
||||
|
||||
var partialArgs = obj.args ? Array.prototype.slice.call(obj.args, 0) : [];
|
||||
var callbackArgIndex = isFinite(obj.ok) ? obj.ok : obj.args ? obj.args.length : undefined;
|
||||
var errorbackArgIndex = obj.ng;
|
||||
var target = obj.target;
|
||||
|
||||
return function () {
|
||||
var d = new Deferred();
|
||||
var d = new Deferred().next(function (args) {
|
||||
var next = this._next.callback.ok;
|
||||
this._next.callback.ok = function () {
|
||||
return next.apply(this, args.args);
|
||||
};
|
||||
});
|
||||
|
||||
d.next = function (fun) { return this._post("ok", function () {
|
||||
fun.apply(this, (arguments[0] instanceof Deferred.Arguments) ? arguments[0].args : arguments);
|
||||
}) };
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var args = partialArgs.concat(Array.prototype.slice.call(arguments, 0));
|
||||
if (!(isFinite(callbackArgIndex) && callbackArgIndex !== null)) {
|
||||
callbackArgIndex = args.length;
|
||||
}
|
||||
@ -481,24 +336,10 @@ Deferred.connect = function (func, obj) {
|
||||
Deferred.next(function () { func.apply(target, args) });
|
||||
return d;
|
||||
}
|
||||
}
|
||||
};
|
||||
Deferred.Arguments = function (args) { this.args = Array.prototype.slice.call(args, 0) };
|
||||
|
||||
/* Deferred.retry(retryCount, func [, options = { wait : 0 } ])
|
||||
*
|
||||
* Try func (returns Deferred) max `retryCount`.
|
||||
*
|
||||
* Sample::
|
||||
* Deferred.retry(3, function () {
|
||||
* return http.get(...);
|
||||
* }).
|
||||
* next(function (res) {
|
||||
* res //=> response if succeeded
|
||||
* }).
|
||||
* error(function (e) {
|
||||
* e //=> error if all try failed
|
||||
* });
|
||||
*/
|
||||
Deferred.retry = function (retryCount, funcDeferred/* funcDeferred() return Deferred */, options) {
|
||||
Deferred.retry = function (retryCount, funcDeferred, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
var wait = options.wait || 0;
|
||||
@ -519,10 +360,11 @@ Deferred.retry = function (retryCount, funcDeferred/* funcDeferred() return Defe
|
||||
};
|
||||
setTimeout(retry, 0);
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
Deferred.methods = ["parallel", "wait", "next", "call", "loop", "repeat", "chain"];
|
||||
Deferred.define = function (obj, list) {
|
||||
if (!list) list = ["parallel", "wait", "next", "call", "loop", "repeat"];
|
||||
if (!list) list = Deferred.methods;
|
||||
if (!obj) obj = (function getGlobal () { return this })();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var n = list[i];
|
||||
@ -531,3 +373,4 @@ Deferred.define = function (obj, list) {
|
||||
return Deferred;
|
||||
};
|
||||
|
||||
this.Deferred = Deferred;// End of JSDeferred
|
||||
|
Loading…
x
Reference in New Issue
Block a user