Promise.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. var Class = require('./Class');
  2. var isObj = require('./isObj');
  3. var isFn = require('./isFn');
  4. var State = require('./State');
  5. var bind = require('./bind');
  6. var nextTick = require('./nextTick');
  7. var noop = require('./noop');
  8. var toArr = require('./toArr');
  9. var Promise = (exports = Class(
  10. {
  11. initialize: function Promise(fn) {
  12. if (!isObj(this))
  13. throw new TypeError('Promises must be constructed via new');
  14. if (!isFn(fn)) throw new TypeError(fn + ' is not a function');
  15. var self = this;
  16. this._state = new State('pending', {
  17. fulfill: {
  18. from: 'pending',
  19. to: 'fulfilled'
  20. },
  21. reject: {
  22. from: 'pending',
  23. to: 'rejected'
  24. },
  25. adopt: {
  26. from: 'pending',
  27. to: 'adopted'
  28. }
  29. })
  30. .on('fulfill', assignVal)
  31. .on('reject', assignVal)
  32. .on('adopt', assignVal);
  33. function assignVal(val) {
  34. self._value = val;
  35. }
  36. this._handled = false;
  37. this._value = undefined;
  38. this._deferreds = [];
  39. doResolve(fn, this);
  40. },
  41. catch: function(onRejected) {
  42. return this.then(null, onRejected);
  43. },
  44. then: function(onFulfilled, onRejected) {
  45. var promise = new Promise(noop);
  46. handle(this, new Handler(onFulfilled, onRejected, promise));
  47. return promise;
  48. }
  49. },
  50. {
  51. all: function(arr) {
  52. var args = toArr(arr);
  53. return new Promise(function(resolve, reject) {
  54. if (args.length === 0) return resolve([]);
  55. var remaining = args.length;
  56. function res(i, val) {
  57. try {
  58. if (val && (isObj(val) || isFn(val))) {
  59. var then = val.then;
  60. if (isFn(then)) {
  61. then.call(
  62. val,
  63. function(val) {
  64. res(i, val);
  65. },
  66. reject
  67. );
  68. return;
  69. }
  70. }
  71. args[i] = val;
  72. if (--remaining === 0) resolve(args);
  73. } catch (e) {
  74. reject(e);
  75. }
  76. }
  77. for (var i = 0; i < args.length; i++) res(i, args[i]);
  78. });
  79. },
  80. resolve: function(val) {
  81. if (val && isObj(val) && val.constructor === Promise) return val;
  82. return new Promise(function(resolve) {
  83. resolve(val);
  84. });
  85. },
  86. reject: function(val) {
  87. return new Promise(function(resolve, reject) {
  88. reject(val);
  89. });
  90. },
  91. race: function(values) {
  92. return new Promise(function(resolve, reject) {
  93. for (var i = 0, len = values.length; i < len; i++) {
  94. values[i].then(resolve, reject);
  95. }
  96. });
  97. }
  98. }
  99. ));
  100. var Handler = Class({
  101. initialize: function Handler(onFulfilled, onRejected, promise) {
  102. this.onFulfilled = isFn(onFulfilled) ? onFulfilled : null;
  103. this.onRejected = isFn(onRejected) ? onRejected : null;
  104. this.promise = promise;
  105. }
  106. });
  107. function reject(self, err) {
  108. self._state.reject(err);
  109. finale(self);
  110. }
  111. function resolve(self, val) {
  112. try {
  113. if (val === self)
  114. throw new TypeError('A promise cannot be resolved with itself');
  115. if (val && (isObj(val) || isFn(val))) {
  116. var then = val.then;
  117. if (val instanceof Promise) {
  118. self._state.adopt(val);
  119. return finale(self);
  120. }
  121. if (isFn(then)) return doResolve(bind(then, val), self);
  122. }
  123. self._state.fulfill(val);
  124. finale(self);
  125. } catch (e) {
  126. reject(self, e);
  127. }
  128. }
  129. function finale(self) {
  130. for (var i = 0, len = self._deferreds.length; i < len; i++) {
  131. handle(self, self._deferreds[i]);
  132. }
  133. self._deferreds = null;
  134. }
  135. function handle(self, deferred) {
  136. while (self._state.is('adopted')) self = self._value;
  137. if (self._state.is('pending')) return self._deferreds.push(deferred);
  138. self._handled = true;
  139. nextTick(function() {
  140. var isFulfilled = self._state.is('fulfilled');
  141. var cb = isFulfilled ? deferred.onFulfilled : deferred.onRejected;
  142. if (cb === null)
  143. return (isFulfilled ? resolve : reject)(
  144. deferred.promise,
  145. self._value
  146. );
  147. var ret;
  148. try {
  149. ret = cb(self._value);
  150. } catch (e) {
  151. return reject(deferred.promise, e);
  152. }
  153. resolve(deferred.promise, ret);
  154. });
  155. }
  156. function doResolve(fn, self) {
  157. var done = false;
  158. try {
  159. fn(
  160. function(val) {
  161. if (done) return;
  162. done = true;
  163. resolve(self, val);
  164. },
  165. function(reason) {
  166. if (done) return;
  167. done = true;
  168. reject(self, reason);
  169. }
  170. );
  171. } catch (e) {
  172. if (done) return;
  173. done = true;
  174. reject(self, e);
  175. }
  176. }
  177. module.exports = exports;