-internal.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import {
  2. objectOrFunction,
  3. isFunction
  4. } from './utils';
  5. import {
  6. asap
  7. } from './asap';
  8. import originalThen from './then';
  9. import originalResolve from './promise/resolve';
  10. export const PROMISE_ID = Math.random().toString(36).substring(2);
  11. function noop() {}
  12. const PENDING = void 0;
  13. const FULFILLED = 1;
  14. const REJECTED = 2;
  15. const TRY_CATCH_ERROR = { error: null };
  16. function selfFulfillment() {
  17. return new TypeError("You cannot resolve a promise with itself");
  18. }
  19. function cannotReturnOwn() {
  20. return new TypeError('A promises callback cannot return that same promise.');
  21. }
  22. function getThen(promise) {
  23. try {
  24. return promise.then;
  25. } catch(error) {
  26. TRY_CATCH_ERROR.error = error;
  27. return TRY_CATCH_ERROR;
  28. }
  29. }
  30. function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
  31. try {
  32. then.call(value, fulfillmentHandler, rejectionHandler);
  33. } catch(e) {
  34. return e;
  35. }
  36. }
  37. function handleForeignThenable(promise, thenable, then) {
  38. asap(promise => {
  39. var sealed = false;
  40. var error = tryThen(then, thenable, value => {
  41. if (sealed) { return; }
  42. sealed = true;
  43. if (thenable !== value) {
  44. resolve(promise, value);
  45. } else {
  46. fulfill(promise, value);
  47. }
  48. }, reason => {
  49. if (sealed) { return; }
  50. sealed = true;
  51. reject(promise, reason);
  52. }, 'Settle: ' + (promise._label || ' unknown promise'));
  53. if (!sealed && error) {
  54. sealed = true;
  55. reject(promise, error);
  56. }
  57. }, promise);
  58. }
  59. function handleOwnThenable(promise, thenable) {
  60. if (thenable._state === FULFILLED) {
  61. fulfill(promise, thenable._result);
  62. } else if (thenable._state === REJECTED) {
  63. reject(promise, thenable._result);
  64. } else {
  65. subscribe(thenable, undefined, value => resolve(promise, value),
  66. reason => reject(promise, reason))
  67. }
  68. }
  69. function handleMaybeThenable(promise, maybeThenable, then) {
  70. if (maybeThenable.constructor === promise.constructor &&
  71. then === originalThen &&
  72. maybeThenable.constructor.resolve === originalResolve) {
  73. handleOwnThenable(promise, maybeThenable);
  74. } else {
  75. if (then === TRY_CATCH_ERROR) {
  76. reject(promise, TRY_CATCH_ERROR.error);
  77. TRY_CATCH_ERROR.error = null;
  78. } else if (then === undefined) {
  79. fulfill(promise, maybeThenable);
  80. } else if (isFunction(then)) {
  81. handleForeignThenable(promise, maybeThenable, then);
  82. } else {
  83. fulfill(promise, maybeThenable);
  84. }
  85. }
  86. }
  87. function resolve(promise, value) {
  88. if (promise === value) {
  89. reject(promise, selfFulfillment());
  90. } else if (objectOrFunction(value)) {
  91. handleMaybeThenable(promise, value, getThen(value));
  92. } else {
  93. fulfill(promise, value);
  94. }
  95. }
  96. function publishRejection(promise) {
  97. if (promise._onerror) {
  98. promise._onerror(promise._result);
  99. }
  100. publish(promise);
  101. }
  102. function fulfill(promise, value) {
  103. if (promise._state !== PENDING) { return; }
  104. promise._result = value;
  105. promise._state = FULFILLED;
  106. if (promise._subscribers.length !== 0) {
  107. asap(publish, promise);
  108. }
  109. }
  110. function reject(promise, reason) {
  111. if (promise._state !== PENDING) { return; }
  112. promise._state = REJECTED;
  113. promise._result = reason;
  114. asap(publishRejection, promise);
  115. }
  116. function subscribe(parent, child, onFulfillment, onRejection) {
  117. let { _subscribers } = parent;
  118. let { length } = _subscribers;
  119. parent._onerror = null;
  120. _subscribers[length] = child;
  121. _subscribers[length + FULFILLED] = onFulfillment;
  122. _subscribers[length + REJECTED] = onRejection;
  123. if (length === 0 && parent._state) {
  124. asap(publish, parent);
  125. }
  126. }
  127. function publish(promise) {
  128. let subscribers = promise._subscribers;
  129. let settled = promise._state;
  130. if (subscribers.length === 0) { return; }
  131. let child, callback, detail = promise._result;
  132. for (let i = 0; i < subscribers.length; i += 3) {
  133. child = subscribers[i];
  134. callback = subscribers[i + settled];
  135. if (child) {
  136. invokeCallback(settled, child, callback, detail);
  137. } else {
  138. callback(detail);
  139. }
  140. }
  141. promise._subscribers.length = 0;
  142. }
  143. function tryCatch(callback, detail) {
  144. try {
  145. return callback(detail);
  146. } catch(e) {
  147. TRY_CATCH_ERROR.error = e;
  148. return TRY_CATCH_ERROR;
  149. }
  150. }
  151. function invokeCallback(settled, promise, callback, detail) {
  152. let hasCallback = isFunction(callback),
  153. value, error, succeeded, failed;
  154. if (hasCallback) {
  155. value = tryCatch(callback, detail);
  156. if (value === TRY_CATCH_ERROR) {
  157. failed = true;
  158. error = value.error;
  159. value.error = null;
  160. } else {
  161. succeeded = true;
  162. }
  163. if (promise === value) {
  164. reject(promise, cannotReturnOwn());
  165. return;
  166. }
  167. } else {
  168. value = detail;
  169. succeeded = true;
  170. }
  171. if (promise._state !== PENDING) {
  172. // noop
  173. } else if (hasCallback && succeeded) {
  174. resolve(promise, value);
  175. } else if (failed) {
  176. reject(promise, error);
  177. } else if (settled === FULFILLED) {
  178. fulfill(promise, value);
  179. } else if (settled === REJECTED) {
  180. reject(promise, value);
  181. }
  182. }
  183. function initializePromise(promise, resolver) {
  184. try {
  185. resolver(function resolvePromise(value){
  186. resolve(promise, value);
  187. }, function rejectPromise(reason) {
  188. reject(promise, reason);
  189. });
  190. } catch(e) {
  191. reject(promise, e);
  192. }
  193. }
  194. let id = 0;
  195. function nextId() {
  196. return id++;
  197. }
  198. function makePromise(promise) {
  199. promise[PROMISE_ID] = id++;
  200. promise._state = undefined;
  201. promise._result = undefined;
  202. promise._subscribers = [];
  203. }
  204. export {
  205. nextId,
  206. makePromise,
  207. getThen,
  208. noop,
  209. resolve,
  210. reject,
  211. fulfill,
  212. subscribe,
  213. publish,
  214. publishRejection,
  215. initializePromise,
  216. invokeCallback,
  217. FULFILLED,
  218. REJECTED,
  219. PENDING,
  220. handleMaybeThenable
  221. };