promise.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. window.Tracker = window.Tracker || {};
  2. /**
  3. * Tracker.Promise
  4. */
  5. Tracker.Promise = function () {
  6. var concat = [].concat;
  7. var promise = function () {
  8. var list;
  9. list = this.list = arguments.length ?
  10. concat.apply([], arguments[0]) : null;
  11. this.resolves = [];
  12. this.rejects = [];
  13. this.resolveValues = [];
  14. this.rejectValues = [];
  15. this.parents = [];
  16. this.state = "pending";
  17. this.fired = false;
  18. if (list)
  19. for (var i = 0, l = list.length; i < l; i++)
  20. list[i].parents.push(this);
  21. };
  22. promise.prototype = {
  23. resolve: function (arg) {
  24. if (this.state == "pending")
  25. this.state = "resolved",
  26. this.resolveValues = concat.apply([], arguments)
  27. this.fire();
  28. },
  29. reject: function (arg) {
  30. if (this.state == "pending")
  31. this.state = "rejected",
  32. this.rejectValues = concat.apply([], arguments)
  33. this.fire();
  34. },
  35. then: function (resolved, rejected) {
  36. if (resolved)
  37. this.resolves.push(resolved);
  38. if (rejected)
  39. this.rejects.push(rejected);
  40. if (this.fired)
  41. switch (this.state) {
  42. case "resolved":
  43. resolved &&
  44. resolved.apply(null, this.resolveValues);
  45. break;
  46. case "rejected":
  47. rejected &&
  48. rejected.apply(null, this.rejectValues);
  49. }
  50. else
  51. this.fire();
  52. return this;
  53. },
  54. fire: function () {
  55. var callbacks, values, list = this.list, allResolved = true,
  56. allResolveValues, parents;
  57. if (this.fired)
  58. return;
  59. if (list && this.state == "pending") {
  60. allResolveValues = [];
  61. for (var i = 0, l = list.length; i < l; i++) {
  62. switch (list[i].state) {
  63. case "pending":
  64. allResolved = false;
  65. break;
  66. case "resolved":
  67. allResolveValues[i] =
  68. list[i].resolveValues[0];
  69. break;
  70. case "rejected":
  71. return this.reject(list[i].rejectValues[0]);
  72. }
  73. }
  74. if (allResolved)
  75. return this.resolve(allResolveValues);
  76. }
  77. if (this.state == "pending")
  78. return;
  79. if (this.state == "resolved")
  80. callbacks = this.resolves,
  81. values = this.resolveValues;
  82. else if (this.state == "rejected")
  83. callbacks = this.rejects,
  84. values = this.rejectValues;
  85. for (var i = 0, l = callbacks.length; i < l; i++)
  86. callbacks[i].apply(null, values);
  87. this.fired = true;
  88. parents = this.parents;
  89. for (var i = 0, l = parents.length; i < l; i++)
  90. parents[i].fire();
  91. }
  92. };
  93. promise.when = function () {
  94. return new promise(arguments);
  95. };
  96. promise.fuze = function () {
  97. var queue = [], fn, infire, args;
  98. fn = function (process) {
  99. infire ? process() : queue.push(process);
  100. };
  101. fn.fire = function () {
  102. while (queue.length)
  103. queue.shift().apply(null, arguments);
  104. fn.fired = infire = true;
  105. };
  106. return fn;
  107. };
  108. return promise;
  109. }();