es.promise.constructor.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. 'use strict';
  2. var $ = require('../internals/export');
  3. var IS_PURE = require('../internals/is-pure');
  4. var IS_NODE = require('../internals/engine-is-node');
  5. var global = require('../internals/global');
  6. var call = require('../internals/function-call');
  7. var redefine = require('../internals/redefine');
  8. var redefineAll = require('../internals/redefine-all');
  9. var setPrototypeOf = require('../internals/object-set-prototype-of');
  10. var setToStringTag = require('../internals/set-to-string-tag');
  11. var setSpecies = require('../internals/set-species');
  12. var aCallable = require('../internals/a-callable');
  13. var isCallable = require('../internals/is-callable');
  14. var isObject = require('../internals/is-object');
  15. var anInstance = require('../internals/an-instance');
  16. var speciesConstructor = require('../internals/species-constructor');
  17. var task = require('../internals/task').set;
  18. var microtask = require('../internals/microtask');
  19. var hostReportErrors = require('../internals/host-report-errors');
  20. var perform = require('../internals/perform');
  21. var Queue = require('../internals/queue');
  22. var InternalStateModule = require('../internals/internal-state');
  23. var NativePromiseConstructor = require('../internals/promise-native-constructor');
  24. var PromiseConstructorDetection = require('../internals/promise-constructor-detection');
  25. var newPromiseCapabilityModule = require('../internals/new-promise-capability');
  26. var PROMISE = 'Promise';
  27. var FORCED_PROMISE_CONSTRUCTOR = PromiseConstructorDetection.CONSTRUCTOR;
  28. var NATIVE_PROMISE_REJECTION_EVENT = PromiseConstructorDetection.REJECTION_EVENT;
  29. var NATIVE_PROMISE_SUBCLASSING = PromiseConstructorDetection.SUBCLASSING;
  30. var getInternalPromiseState = InternalStateModule.getterFor(PROMISE);
  31. var setInternalState = InternalStateModule.set;
  32. var NativePromisePrototype = NativePromiseConstructor && NativePromiseConstructor.prototype;
  33. var PromiseConstructor = NativePromiseConstructor;
  34. var PromisePrototype = NativePromisePrototype;
  35. var TypeError = global.TypeError;
  36. var document = global.document;
  37. var process = global.process;
  38. var newPromiseCapability = newPromiseCapabilityModule.f;
  39. var newGenericPromiseCapability = newPromiseCapability;
  40. var DISPATCH_EVENT = !!(document && document.createEvent && global.dispatchEvent);
  41. var UNHANDLED_REJECTION = 'unhandledrejection';
  42. var REJECTION_HANDLED = 'rejectionhandled';
  43. var PENDING = 0;
  44. var FULFILLED = 1;
  45. var REJECTED = 2;
  46. var HANDLED = 1;
  47. var UNHANDLED = 2;
  48. var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
  49. // helpers
  50. var isThenable = function (it) {
  51. var then;
  52. return isObject(it) && isCallable(then = it.then) ? then : false;
  53. };
  54. var callReaction = function (reaction, state) {
  55. var value = state.value;
  56. var ok = state.state == FULFILLED;
  57. var handler = ok ? reaction.ok : reaction.fail;
  58. var resolve = reaction.resolve;
  59. var reject = reaction.reject;
  60. var domain = reaction.domain;
  61. var result, then, exited;
  62. try {
  63. if (handler) {
  64. if (!ok) {
  65. if (state.rejection === UNHANDLED) onHandleUnhandled(state);
  66. state.rejection = HANDLED;
  67. }
  68. if (handler === true) result = value;
  69. else {
  70. if (domain) domain.enter();
  71. result = handler(value); // can throw
  72. if (domain) {
  73. domain.exit();
  74. exited = true;
  75. }
  76. }
  77. if (result === reaction.promise) {
  78. reject(TypeError('Promise-chain cycle'));
  79. } else if (then = isThenable(result)) {
  80. call(then, result, resolve, reject);
  81. } else resolve(result);
  82. } else reject(value);
  83. } catch (error) {
  84. if (domain && !exited) domain.exit();
  85. reject(error);
  86. }
  87. };
  88. var notify = function (state, isReject) {
  89. if (state.notified) return;
  90. state.notified = true;
  91. microtask(function () {
  92. var reactions = state.reactions;
  93. var reaction;
  94. while (reaction = reactions.get()) {
  95. callReaction(reaction, state);
  96. }
  97. state.notified = false;
  98. if (isReject && !state.rejection) onUnhandled(state);
  99. });
  100. };
  101. var dispatchEvent = function (name, promise, reason) {
  102. var event, handler;
  103. if (DISPATCH_EVENT) {
  104. event = document.createEvent('Event');
  105. event.promise = promise;
  106. event.reason = reason;
  107. event.initEvent(name, false, true);
  108. global.dispatchEvent(event);
  109. } else event = { promise: promise, reason: reason };
  110. if (!NATIVE_PROMISE_REJECTION_EVENT && (handler = global['on' + name])) handler(event);
  111. else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
  112. };
  113. var onUnhandled = function (state) {
  114. call(task, global, function () {
  115. var promise = state.facade;
  116. var value = state.value;
  117. var IS_UNHANDLED = isUnhandled(state);
  118. var result;
  119. if (IS_UNHANDLED) {
  120. result = perform(function () {
  121. if (IS_NODE) {
  122. process.emit('unhandledRejection', value, promise);
  123. } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
  124. });
  125. // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
  126. state.rejection = IS_NODE || isUnhandled(state) ? UNHANDLED : HANDLED;
  127. if (result.error) throw result.value;
  128. }
  129. });
  130. };
  131. var isUnhandled = function (state) {
  132. return state.rejection !== HANDLED && !state.parent;
  133. };
  134. var onHandleUnhandled = function (state) {
  135. call(task, global, function () {
  136. var promise = state.facade;
  137. if (IS_NODE) {
  138. process.emit('rejectionHandled', promise);
  139. } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
  140. });
  141. };
  142. var bind = function (fn, state, unwrap) {
  143. return function (value) {
  144. fn(state, value, unwrap);
  145. };
  146. };
  147. var internalReject = function (state, value, unwrap) {
  148. if (state.done) return;
  149. state.done = true;
  150. if (unwrap) state = unwrap;
  151. state.value = value;
  152. state.state = REJECTED;
  153. notify(state, true);
  154. };
  155. var internalResolve = function (state, value, unwrap) {
  156. if (state.done) return;
  157. state.done = true;
  158. if (unwrap) state = unwrap;
  159. try {
  160. if (state.facade === value) throw TypeError("Promise can't be resolved itself");
  161. var then = isThenable(value);
  162. if (then) {
  163. microtask(function () {
  164. var wrapper = { done: false };
  165. try {
  166. call(then, value,
  167. bind(internalResolve, wrapper, state),
  168. bind(internalReject, wrapper, state)
  169. );
  170. } catch (error) {
  171. internalReject(wrapper, error, state);
  172. }
  173. });
  174. } else {
  175. state.value = value;
  176. state.state = FULFILLED;
  177. notify(state, false);
  178. }
  179. } catch (error) {
  180. internalReject({ done: false }, error, state);
  181. }
  182. };
  183. // constructor polyfill
  184. if (FORCED_PROMISE_CONSTRUCTOR) {
  185. // 25.4.3.1 Promise(executor)
  186. PromiseConstructor = function Promise(executor) {
  187. anInstance(this, PromisePrototype);
  188. aCallable(executor);
  189. call(Internal, this);
  190. var state = getInternalPromiseState(this);
  191. try {
  192. executor(bind(internalResolve, state), bind(internalReject, state));
  193. } catch (error) {
  194. internalReject(state, error);
  195. }
  196. };
  197. PromisePrototype = PromiseConstructor.prototype;
  198. // eslint-disable-next-line no-unused-vars -- required for `.length`
  199. Internal = function Promise(executor) {
  200. setInternalState(this, {
  201. type: PROMISE,
  202. done: false,
  203. notified: false,
  204. parent: false,
  205. reactions: new Queue(),
  206. rejection: false,
  207. state: PENDING,
  208. value: undefined
  209. });
  210. };
  211. Internal.prototype = redefineAll(PromisePrototype, {
  212. // `Promise.prototype.then` method
  213. // https://tc39.es/ecma262/#sec-promise.prototype.then
  214. // eslint-disable-next-line unicorn/no-thenable -- safe
  215. then: function then(onFulfilled, onRejected) {
  216. var state = getInternalPromiseState(this);
  217. var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));
  218. state.parent = true;
  219. reaction.ok = isCallable(onFulfilled) ? onFulfilled : true;
  220. reaction.fail = isCallable(onRejected) && onRejected;
  221. reaction.domain = IS_NODE ? process.domain : undefined;
  222. if (state.state == PENDING) state.reactions.add(reaction);
  223. else microtask(function () {
  224. callReaction(reaction, state);
  225. });
  226. return reaction.promise;
  227. }
  228. });
  229. OwnPromiseCapability = function () {
  230. var promise = new Internal();
  231. var state = getInternalPromiseState(promise);
  232. this.promise = promise;
  233. this.resolve = bind(internalResolve, state);
  234. this.reject = bind(internalReject, state);
  235. };
  236. newPromiseCapabilityModule.f = newPromiseCapability = function (C) {
  237. return C === PromiseConstructor || C === PromiseWrapper
  238. ? new OwnPromiseCapability(C)
  239. : newGenericPromiseCapability(C);
  240. };
  241. if (!IS_PURE && isCallable(NativePromiseConstructor) && NativePromisePrototype !== Object.prototype) {
  242. nativeThen = NativePromisePrototype.then;
  243. if (!NATIVE_PROMISE_SUBCLASSING) {
  244. // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
  245. redefine(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
  246. var that = this;
  247. return new PromiseConstructor(function (resolve, reject) {
  248. call(nativeThen, that, resolve, reject);
  249. }).then(onFulfilled, onRejected);
  250. // https://github.com/zloirock/core-js/issues/640
  251. }, { unsafe: true });
  252. }
  253. // make `.constructor === Promise` work for native promise-based APIs
  254. try {
  255. delete NativePromisePrototype.constructor;
  256. } catch (error) { /* empty */ }
  257. // make `instanceof Promise` work for native promise-based APIs
  258. if (setPrototypeOf) {
  259. setPrototypeOf(NativePromisePrototype, PromisePrototype);
  260. }
  261. }
  262. }
  263. $({ global: true, wrap: true, forced: FORCED_PROMISE_CONSTRUCTOR }, {
  264. Promise: PromiseConstructor
  265. });
  266. setToStringTag(PromiseConstructor, PROMISE, false, true);
  267. setSpecies(PROMISE);