jsdeferred.jquery.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // JSDeferred 0.4.0 Copyright (c) 2007 cho45 ( www.lowreal.net )
  2. // See http://github.com/cho45/jsdeferred
  3. function Deferred () { return (this instanceof Deferred) ? this.init() : new Deferred() }
  4. Deferred.ok = function (x) { return x };
  5. Deferred.ng = function (x) { throw x };
  6. Deferred.prototype = {
  7. _id : 0xe38286e381ae,
  8. init : function () {
  9. this._next = null;
  10. this.callback = {
  11. ok: Deferred.ok,
  12. ng: Deferred.ng
  13. };
  14. return this;
  15. },
  16. next : function (fun) { return this._post("ok", fun) },
  17. error : function (fun) { return this._post("ng", fun) },
  18. call : function (val) { return this._fire("ok", val) },
  19. fail : function (err) { return this._fire("ng", err) },
  20. cancel : function () {
  21. (this.canceller || function () {})();
  22. return this.init();
  23. },
  24. _post : function (okng, fun) {
  25. this._next = new Deferred();
  26. this._next.callback[okng] = fun;
  27. return this._next;
  28. },
  29. _fire : function (okng, value) {
  30. var next = "ok";
  31. try {
  32. value = this.callback[okng].call(this, value);
  33. } catch (e) {
  34. next = "ng";
  35. value = e;
  36. if (Deferred.onerror) Deferred.onerror(e);
  37. }
  38. if (Deferred.isDeferred(value)) {
  39. value._next = this._next;
  40. } else {
  41. if (this._next) this._next._fire(next, value);
  42. }
  43. return this;
  44. }
  45. };
  46. Deferred.isDeferred = function (obj) {
  47. return !!(obj && obj._id === Deferred.prototype._id);
  48. };
  49. Deferred.next_default = function (fun) {
  50. var d = new Deferred();
  51. var id = setTimeout(function () { d.call() }, 0);
  52. d.canceller = function () { clearTimeout(id) };
  53. if (fun) d.callback.ok = fun;
  54. return d;
  55. };
  56. Deferred.next_faster_way_readystatechange = ((typeof window === 'object') && (location.protocol == "http:") && !window.opera && /\bMSIE\b/.test(navigator.userAgent)) && function (fun) {
  57. var d = new Deferred();
  58. var t = new Date().getTime();
  59. if (t - arguments.callee._prev_timeout_called < 150) {
  60. var cancel = false;
  61. var script = document.createElement("script");
  62. script.type = "text/javascript";
  63. script.src = "data:text/javascript,";
  64. script.onreadystatechange = function () {
  65. if (!cancel) {
  66. d.canceller();
  67. d.call();
  68. }
  69. };
  70. d.canceller = function () {
  71. if (!cancel) {
  72. cancel = true;
  73. script.onreadystatechange = null;
  74. document.body.removeChild(script);
  75. }
  76. };
  77. document.body.appendChild(script);
  78. } else {
  79. arguments.callee._prev_timeout_called = t;
  80. var id = setTimeout(function () { d.call() }, 0);
  81. d.canceller = function () { clearTimeout(id) };
  82. }
  83. if (fun) d.callback.ok = fun;
  84. return d;
  85. };
  86. Deferred.next_faster_way_Image = ((typeof window === 'object') && (typeof(Image) != "undefined") && !window.opera && document.addEventListener) && function (fun) {
  87. var d = new Deferred();
  88. var img = new Image();
  89. var handler = function () {
  90. d.canceller();
  91. d.call();
  92. };
  93. img.addEventListener("load", handler, false);
  94. img.addEventListener("error", handler, false);
  95. d.canceller = function () {
  96. img.removeEventListener("load", handler, false);
  97. img.removeEventListener("error", handler, false);
  98. };
  99. img.src = "data:image/png," + Math.random();
  100. if (fun) d.callback.ok = fun;
  101. return d;
  102. };
  103. Deferred.next_tick = (typeof process === 'object' && typeof process.nextTick === 'function') && function (fun) {
  104. var d = new Deferred();
  105. process.nextTick(function() { d.call() });
  106. if (fun) d.callback.ok = fun;
  107. return d;
  108. };
  109. Deferred.next =
  110. Deferred.next_faster_way_readystatechange ||
  111. Deferred.next_faster_way_Image ||
  112. Deferred.next_tick ||
  113. Deferred.next_default;
  114. Deferred.chain = function () {
  115. var chain = Deferred.next();
  116. for (var i = 0, len = arguments.length; i < len; i++) (function (obj) {
  117. switch (typeof obj) {
  118. case "function":
  119. var name = null;
  120. try {
  121. name = obj.toString().match(/^\s*function\s+([^\s()]+)/)[1];
  122. } catch (e) { }
  123. if (name != "error") {
  124. chain = chain.next(obj);
  125. } else {
  126. chain = chain.error(obj);
  127. }
  128. break;
  129. case "object":
  130. chain = chain.next(function() { return Deferred.parallel(obj) });
  131. break;
  132. default:
  133. throw "unknown type in process chains";
  134. }
  135. })(arguments[i]);
  136. return chain;
  137. };
  138. Deferred.wait = function (n) {
  139. var d = new Deferred(), t = new Date();
  140. var id = setTimeout(function () {
  141. d.call((new Date()).getTime() - t.getTime());
  142. }, n * 1000);
  143. d.canceller = function () { clearTimeout(id) };
  144. return d;
  145. };
  146. Deferred.call = function (fun) {
  147. var args = Array.prototype.slice.call(arguments, 1);
  148. return Deferred.next(function () {
  149. return fun.apply(this, args);
  150. });
  151. };
  152. Deferred.parallel = function (dl) {
  153. var isArray = false;
  154. if (arguments.length > 1) {
  155. dl = Array.prototype.slice.call(arguments);
  156. isArray = true;
  157. } else if (Array.isArray && Array.isArray(dl) || typeof dl.length == "number") {
  158. isArray = true;
  159. }
  160. var ret = new Deferred(), values = {}, num = 0;
  161. for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
  162. if (typeof d == "function") dl[i] = d = Deferred.next(d);
  163. d.next(function (v) {
  164. values[i] = v;
  165. if (--num <= 0) {
  166. if (isArray) {
  167. values.length = dl.length;
  168. values = Array.prototype.slice.call(values, 0);
  169. }
  170. ret.call(values);
  171. }
  172. }).error(function (e) {
  173. ret.fail(e);
  174. });
  175. num++;
  176. })(dl[i], i);
  177. if (!num) Deferred.next(function () { ret.call() });
  178. ret.canceller = function () {
  179. for (var i in dl) if (dl.hasOwnProperty(i)) {
  180. dl[i].cancel();
  181. }
  182. };
  183. return ret;
  184. };
  185. Deferred.earlier = function (dl) {
  186. var isArray = false;
  187. if (arguments.length > 1) {
  188. dl = Array.prototype.slice.call(arguments);
  189. isArray = true;
  190. } else if (Array.isArray && Array.isArray(dl) || typeof dl.length == "number") {
  191. isArray = true;
  192. }
  193. var ret = new Deferred(), values = {}, num = 0;
  194. for (var i in dl) if (dl.hasOwnProperty(i)) (function (d, i) {
  195. d.next(function (v) {
  196. values[i] = v;
  197. if (isArray) {
  198. values.length = dl.length;
  199. values = Array.prototype.slice.call(values, 0);
  200. }
  201. ret.call(values);
  202. ret.canceller();
  203. }).error(function (e) {
  204. ret.fail(e);
  205. });
  206. num++;
  207. })(dl[i], i);
  208. if (!num) Deferred.next(function () { ret.call() });
  209. ret.canceller = function () {
  210. for (var i in dl) if (dl.hasOwnProperty(i)) {
  211. dl[i].cancel();
  212. }
  213. };
  214. return ret;
  215. };
  216. Deferred.loop = function (n, fun) {
  217. var o = {
  218. begin : n.begin || 0,
  219. end : (typeof n.end == "number") ? n.end : n - 1,
  220. step : n.step || 1,
  221. last : false,
  222. prev : null
  223. };
  224. var ret, step = o.step;
  225. return Deferred.next(function () {
  226. function _loop (i) {
  227. if (i <= o.end) {
  228. if ((i + step) > o.end) {
  229. o.last = true;
  230. o.step = o.end - i + 1;
  231. }
  232. o.prev = ret;
  233. ret = fun.call(this, i, o);
  234. if (Deferred.isDeferred(ret)) {
  235. return ret.next(function (r) {
  236. ret = r;
  237. return Deferred.call(_loop, i + step);
  238. });
  239. } else {
  240. return Deferred.call(_loop, i + step);
  241. }
  242. } else {
  243. return ret;
  244. }
  245. }
  246. return (o.begin <= o.end) ? Deferred.call(_loop, o.begin) : null;
  247. });
  248. };
  249. Deferred.repeat = function (n, fun) {
  250. var i = 0, end = {}, ret = null;
  251. return Deferred.next(function () {
  252. var t = (new Date()).getTime();
  253. do {
  254. if (i >= n) return null;
  255. ret = fun(i++);
  256. } while ((new Date()).getTime() - t < 20);
  257. return Deferred.call(arguments.callee);
  258. });
  259. };
  260. Deferred.register = function (name, fun) {
  261. this.prototype[name] = function () {
  262. var a = arguments;
  263. return this.next(function () {
  264. return fun.apply(this, a);
  265. });
  266. };
  267. };
  268. Deferred.register("loop", Deferred.loop);
  269. Deferred.register("wait", Deferred.wait);
  270. Deferred.connect = function (funo, options) {
  271. var target, func, obj;
  272. if (typeof arguments[1] == "string") {
  273. target = arguments[0];
  274. func = target[arguments[1]];
  275. obj = arguments[2] || {};
  276. } else {
  277. func = arguments[0];
  278. obj = arguments[1] || {};
  279. target = obj.target;
  280. }
  281. var partialArgs = obj.args ? Array.prototype.slice.call(obj.args, 0) : [];
  282. var callbackArgIndex = isFinite(obj.ok) ? obj.ok : obj.args ? obj.args.length : undefined;
  283. var errorbackArgIndex = obj.ng;
  284. return function () {
  285. var d = new Deferred().next(function (args) {
  286. var next = this._next.callback.ok;
  287. this._next.callback.ok = function () {
  288. return next.apply(this, args.args);
  289. };
  290. });
  291. var args = partialArgs.concat(Array.prototype.slice.call(arguments, 0));
  292. if (!(isFinite(callbackArgIndex) && callbackArgIndex !== null)) {
  293. callbackArgIndex = args.length;
  294. }
  295. var callback = function () { d.call(new Deferred.Arguments(arguments)) };
  296. args.splice(callbackArgIndex, 0, callback);
  297. if (isFinite(errorbackArgIndex) && errorbackArgIndex !== null) {
  298. var errorback = function () { d.fail(arguments) };
  299. args.splice(errorbackArgIndex, 0, errorback);
  300. }
  301. Deferred.next(function () { func.apply(target, args) });
  302. return d;
  303. };
  304. };
  305. Deferred.Arguments = function (args) { this.args = Array.prototype.slice.call(args, 0) };
  306. Deferred.retry = function (retryCount, funcDeferred, options) {
  307. if (!options) options = {};
  308. var wait = options.wait || 0;
  309. var d = new Deferred();
  310. var retry = function () {
  311. var m = funcDeferred(retryCount);
  312. m.
  313. next(function (mes) {
  314. d.call(mes);
  315. }).
  316. error(function (e) {
  317. if (--retryCount <= 0) {
  318. d.fail(['retry failed', e]);
  319. } else {
  320. setTimeout(retry, wait * 1000);
  321. }
  322. });
  323. };
  324. setTimeout(retry, 0);
  325. return d;
  326. };
  327. Deferred.methods = ["parallel", "wait", "next", "call", "loop", "repeat", "chain"];
  328. Deferred.define = function (obj, list) {
  329. if (!list) list = Deferred.methods;
  330. if (!obj) obj = (function getGlobal () { return this })();
  331. for (var i = 0; i < list.length; i++) {
  332. var n = list[i];
  333. obj[n] = Deferred[n];
  334. }
  335. return Deferred;
  336. };
  337. this.Deferred = Deferred;
  338. (function ($) {
  339. function wrap (obj) {
  340. obj.toJSDeferred = function () {
  341. return Deferred.absorb(this);
  342. };
  343. obj.next = function (fun) {
  344. return Deferred.absorb(this).next(fun);
  345. };
  346. obj.error = function (fun) {
  347. return Deferred.absorb(this).error(fun);
  348. };
  349. obj.done(function (v) {
  350. if (obj._next) obj._next._fire('ok', v);
  351. });
  352. obj.fail(function (v) {
  353. if (obj._next) obj._next._fire('ok', v);
  354. });
  355. var orig_promise = obj.promise;
  356. obj.promise = function () {
  357. return wrap(orig_promise.apply(this, arguments));
  358. };
  359. return obj;
  360. }
  361. Deferred.absorb = function (obj) {
  362. var ret = new Deferred();
  363. ret.progress = function () {};
  364. obj.done(function (v) {
  365. if (v.toJSDeferred) delete v.toJSDeferred;
  366. ret.call(v);
  367. });
  368. obj.fail(function (v) {
  369. if (v.toJSDeferred) delete v.toJSDeferred;
  370. ret.fail(v);
  371. });
  372. if (obj.progress) obj.progress(function (v) {
  373. ret.progress(v);
  374. });
  375. return ret;
  376. };
  377. var orig_Deferred = $.Deferred;
  378. $.Deferred = function (fun) {
  379. return wrap(orig_Deferred.apply(this, arguments));
  380. };
  381. var orig_ajax = $.ajax;
  382. $.ajax = function () {
  383. return orig_ajax.apply(this, arguments);
  384. };
  385. var orig_isDeferred = Deferred.isDeferred;
  386. Deferred.isDeferred = function (obj) {
  387. return orig_isDeferred(obj) || !!(obj && obj.toJSDeferred);
  388. };
  389. $.JSDeferred = Deferred;
  390. })(jQuery);