polyfill_Promise.js.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: polyfill/Promise.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: polyfill/Promise.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>// Licensed Materials - Property of IBM
  20. //
  21. // IBM Watson Analytics
  22. //
  23. // (C) Copyright IBM Corp. 2015
  24. //
  25. // US Government Users Restricted Rights - Use, duplication or
  26. // disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  27. module.exports = ( function(
  28. ObjectPolyfill,
  29. setImmediate
  30. )
  31. {
  32. "use strict";
  33. /*jshint latedef:false*/
  34. /**
  35. * Helper method that turns an _iterable into an array of promises
  36. * @memberof module:barejs/polyfill.Promise~
  37. * @private
  38. */
  39. function iterableToPromiseArray( _iterable )
  40. {
  41. var promises;
  42. var it;
  43. var value;
  44. if ( _iterable.length || _iterable.length === 0 )
  45. {
  46. promises = new Array( _iterable.length );
  47. for ( var i = 0, len = _iterable.length; i &lt; len; ++i )
  48. {
  49. value = _iterable[i];
  50. if ( ( !value ) || ( typeof value.then !== "function" ) )
  51. value = Promise.resolve( value );
  52. promises[i] = value;
  53. }
  54. }
  55. else if ( ( it = ObjectPolyfill.getIterator( _iterable ) ) )
  56. {
  57. promises = [];
  58. for( value = it.next(); !value.done; value = it.next() )
  59. {
  60. if ( ( !value.value ) || ( typeof value.value.then !== "function" ) )
  61. promises.push( Promise.resolve( value.value ) );
  62. else
  63. promises.push( value.value );
  64. }
  65. }
  66. else
  67. {
  68. throw new Error( "Invalid iterable" );
  69. }
  70. return promises;
  71. }
  72. /**
  73. * Handler for a promise
  74. * @class module:barejs/polyfill.Promise~Handler
  75. * @private
  76. */
  77. function Handler( _onFulfilled, _onRejected, _promise )
  78. {
  79. this.onFulfilled = typeof _onFulfilled === "function" ? _onFulfilled : null;
  80. this.onRejected = typeof _onRejected === "function" ? _onRejected : null;
  81. this.promise = _promise;
  82. }
  83. /**
  84. * No-operation function
  85. */
  86. function noop() {}
  87. // States:
  88. //
  89. // 0 - pending
  90. // 1 - fulfilled with _value
  91. // 2 - rejected with _value
  92. // 3 - adopted the state of another promise, _value
  93. //
  94. // once the state is no longer pending (0) it is immutable
  95. // All `_` prefixed properties will be reduced to `_{random number}`
  96. // at build time to obfuscate them and discourage their use.
  97. // We don't use symbols or Object.defineProperty to fully hide them
  98. // because the performance isn't good enough.
  99. // to avoid using try/catch inside critical functions, we
  100. // extract them to here.
  101. var LAST_ERROR = null;
  102. var IS_ERROR = {};
  103. /**
  104. * Safely request the then function from an object
  105. */
  106. function getThen( _obj )
  107. {
  108. try
  109. {
  110. return _obj.then;
  111. }
  112. catch ( ex )
  113. {
  114. LAST_ERROR = ex;
  115. return IS_ERROR;
  116. }
  117. }
  118. function tryCallOne( _fn, _a )
  119. {
  120. try
  121. {
  122. return _fn( _a );
  123. }
  124. catch ( ex )
  125. {
  126. LAST_ERROR = ex;
  127. return IS_ERROR;
  128. }
  129. }
  130. function tryCallTwo( _fn, _a, _b )
  131. {
  132. try
  133. {
  134. _fn( _a, _b );
  135. }
  136. catch ( ex )
  137. {
  138. LAST_ERROR = ex;
  139. return IS_ERROR;
  140. }
  141. }
  142. /**
  143. * Create a new Promise
  144. * @class module:barejs/polyfill.Promise
  145. * @param {function} _resolver The resolver function that will be called with two callbacks:
  146. * _resolve (call on succes) and _reject (call on failure).
  147. */
  148. function Promise( _resolver )
  149. {
  150. if ( typeof this !== "object" )
  151. throw new TypeError( "Promises must be constructed via new" );
  152. this._state = 0;
  153. this._value = null;
  154. this._deferreds = [];
  155. if ( ObjectPolyfill.ensureCallable( _resolver ) === noop )
  156. return;
  157. doResolve( _resolver, this );
  158. }
  159. function safeThen( _self, _onFulfilled, _onRejected )
  160. {
  161. return new _self.constructor( function( resolve, reject )
  162. {
  163. var res = new Promise( noop );
  164. res.then( resolve, reject );
  165. handle( _self, new Handler( _onFulfilled, _onRejected, res ) );
  166. } );
  167. }
  168. function handle( _self, _deferred )
  169. {
  170. while ( _self._state === 3 )
  171. {
  172. _self = _self._value;
  173. }
  174. if ( _self._state === 0 )
  175. {
  176. _self._deferreds.push( _deferred );
  177. return;
  178. }
  179. setImmediate( function()
  180. {
  181. var cb = _self._state === 1 ? _deferred.onFulfilled : _deferred.onRejected;
  182. if ( cb === null )
  183. {
  184. if ( _self._state === 1 )
  185. {
  186. resolve( _deferred.promise, _self._value );
  187. }
  188. else
  189. {
  190. reject( _deferred.promise, _self._value );
  191. }
  192. return;
  193. }
  194. var ret = tryCallOne( cb, _self._value );
  195. if ( ret === IS_ERROR )
  196. {
  197. reject( _deferred.promise, LAST_ERROR );
  198. }
  199. else
  200. {
  201. resolve( _deferred.promise, ret );
  202. }
  203. } );
  204. }
  205. function resolve( _self, _newValue )
  206. {
  207. // Promise Resolution Procedure:
  208. // https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  209. if ( _newValue === _self )
  210. {
  211. return reject( _self, new TypeError( 'A promise cannot be resolved with itself.' ) );
  212. }
  213. if ( _newValue &amp;&amp; (typeof _newValue === "object" || typeof _newValue === "function") )
  214. {
  215. var then = getThen( _newValue );
  216. if ( then === IS_ERROR )
  217. {
  218. return reject( _self, LAST_ERROR );
  219. }
  220. if ( then === _self.then &amp;&amp; ( _newValue instanceof Promise ) )
  221. {
  222. _self._state = 3;
  223. _self._value = _newValue;
  224. finale( _self );
  225. return;
  226. }
  227. else if ( typeof then === "function" )
  228. {
  229. doResolve( then.bind( _newValue ), _self );
  230. return;
  231. }
  232. }
  233. _self._state = 1;
  234. _self._value = _newValue;
  235. finale( _self );
  236. }
  237. function reject( _self, _newValue )
  238. {
  239. _self._state = 2;
  240. _self._value = _newValue;
  241. finale( _self );
  242. }
  243. function finale( _self )
  244. {
  245. for ( var i = 0; i &lt; _self._deferreds.length; ++i )
  246. handle( _self, _self._deferreds[ i ] );
  247. _self._deferreds = null;
  248. }
  249. /**
  250. * Take a potentially misbehaving resolver function and make sure onFulfilled and onRejected
  251. * are only called once.
  252. *
  253. * Makes no guarantees about asynchrony.
  254. * @memberof module:barejs/polyfill.Promise~
  255. * @private
  256. */
  257. function doResolve( _resolver, _promise )
  258. {
  259. var done = false;
  260. var res = tryCallTwo( _resolver, function( value )
  261. {
  262. if ( done )
  263. return;
  264. done = true;
  265. resolve( _promise, value );
  266. }, function( reason )
  267. {
  268. if ( done )
  269. return;
  270. done = true;
  271. reject( _promise, reason );
  272. } );
  273. if ( !done &amp;&amp; res === IS_ERROR )
  274. {
  275. done = true;
  276. reject( _promise, LAST_ERROR );
  277. }
  278. }
  279. return ObjectPolyfill.polyfill( Promise,
  280. /** @lends module:barejs/polyfill.Promise */
  281. {
  282. _noop: noop,
  283. /**
  284. * The Promise.resolve( _value ) method returns a Promise object that is resolved with the given value.
  285. * If the value is a thenable (i.e. has a then method), the returned promise will "follow" that thenable,
  286. * adopting its eventual state; otherwise the returned promise will be fulfilled with the value.
  287. * @param {*} _value The value to resolve with.
  288. * @returns {module:barejs/polyfill.Promise} A Promise that is resolved with _value.
  289. */
  290. resolve: function resolve( _value )
  291. {
  292. return new Promise( function( _resolve, _reject )
  293. {
  294. _resolve( _value );
  295. } );
  296. },
  297. /**
  298. * The Promise.reject( _reason ) method returns a Promise object that is rejected with the given reason.
  299. * @param {*} _reason The rejection reason (passed as rejection argument).
  300. * @returns {module:barejs/polyfill.Promise} A Promise that is rejected with _reason.
  301. */
  302. reject: function reject( _reason )
  303. {
  304. return new Promise( function( _resolve, _reject )
  305. {
  306. _reject( _reason );
  307. } );
  308. },
  309. /**
  310. * The Promise.all( _iterable ) method returns a promise that resolves when all of the promises
  311. * in the iterable argument have resolved. If any of the passed in promises rejects, the all
  312. * Promise immediately rejects with the value of the promise that rejected, discarding all the
  313. * other promises whether or not they have resolved.
  314. * @param _iterable {Object} Array that can be iterated.
  315. * @returns {module:barejs/polyfill.Promise} A promise that will resolve with an array of values corresponding to all Promises in _iterable, after every Promise is resolved.
  316. */
  317. all: function all( _iterable )
  318. {
  319. var promises = iterableToPromiseArray( _iterable );
  320. if ( promises.length &lt; 1 )
  321. return Promise.resolve( promises );
  322. return new Promise( function( _resolve, _reject )
  323. {
  324. var values = new Array( promises.length );
  325. var resolveCount = 0;
  326. function rejected( _reason )
  327. {
  328. if ( values )
  329. {
  330. _reject( _reason );
  331. values = null;
  332. }
  333. }
  334. function resolved( _index, _value )
  335. {
  336. if ( values )
  337. {
  338. // Promises should never resolve twice, so we don't perform any sanity checking
  339. // to see if values.hasOwnProperty( _index )...
  340. values[_index] = _value;
  341. if ( ++resolveCount >= values.length )
  342. {
  343. _resolve( values );
  344. values = null;
  345. }
  346. }
  347. }
  348. for ( var i = 0, len = promises.length; i &lt; len; ++i )
  349. promises[i].then( resolved.bind( null, i ), rejected );
  350. } );
  351. },
  352. /**
  353. * The Promise.race( _iterable ) method returns a promise that resolves or rejects as soon as one
  354. * of the promises in the iterable resolves or rejects, with the value or reason from that promise.
  355. * @returns {module:barejs/polyfill.Promise} A promise that will resolve with the value of the first Promise to resolve.
  356. */
  357. race: function race( _iterable )
  358. {
  359. var promises = iterableToPromiseArray( _iterable );
  360. return new Promise( function( _resolve, _reject )
  361. {
  362. var isResolved = false;
  363. function rejected( _reason )
  364. {
  365. if ( !isResolved )
  366. {
  367. _reject( _reason );
  368. isResolved = true;
  369. }
  370. }
  371. function resolved( _value )
  372. {
  373. if ( !isResolved )
  374. {
  375. _resolve( _value );
  376. isResolved = true;
  377. }
  378. }
  379. for ( var i = 0, len = promises.length; i &lt; len; ++i )
  380. promises[i].then( resolved, rejected );
  381. } );
  382. }
  383. },
  384. /** @lends module:barejs/polyfill.Promise# */
  385. {
  386. /**
  387. * Register either a resolve or reject callback, or both.
  388. * @returns {module:barejs/polyfill.Promise} A promise that will resolve or reject with the value returned by (or thrown from) _onFulfilled or _onRejected.
  389. */
  390. then: function( _onFulfilled, _onRejected )
  391. {
  392. if ( this.constructor !== Promise )
  393. return safeThen( this, _onFulfilled, _onRejected );
  394. var res = new Promise( noop );
  395. handle( this, new Handler( _onFulfilled, _onRejected, res ) );
  396. return res;
  397. },
  398. /**
  399. * Register a rejection callback (shortcut for then( null, _onRejected ) ).
  400. * @returns {module:barejs/polyfill.Promise} A promise that will resolve or reject with the value returned by (or thrown from) _onRejected.
  401. */
  402. "catch": function( _onRejected )
  403. {
  404. return this.then( null, _onRejected );
  405. }
  406. }, null, "Promise" );
  407. }(
  408. require( "./Object" ),
  409. /* global setImmediate, setTimeout */
  410. typeof setImmediate !== "undefined" ? setImmediate : setTimeout
  411. ) );
  412. </code></pre>
  413. </article>
  414. </section>
  415. </div>
  416. <nav>
  417. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-barejs.html">barejs</a></li><li><a href="module-barejs_polyfill.html">barejs/polyfill</a></li><li><a href="module-barejs_polyfill_Intl.html">barejs/polyfill/Intl</a></li></ul><h3>Classes</h3><ul><li><a href="module-barejs.decl.html">decl</a></li><li><a href="module-barejs.decl-Enum.html">Enum</a></li><li><a href="module-barejs.decl-Interface.html">Interface</a></li><li><a href="module-barejs.decl-SpecialType.html">SpecialType</a></li><li><a href="module-barejs.Destroyable.html">Destroyable</a></li><li><a href="module-barejs.EventArgs.html">EventArgs</a></li><li><a href="module-barejs.Evented.html">Evented</a></li><li><a href="module-barejs.Evented-EventedHandle.html">EventedHandle</a></li><li><a href="module-barejs.Exception.html">Exception</a></li><li><a href="module-barejs_polyfill.Array.html">Array</a></li><li><a href="module-barejs_polyfill.Date.html">Date</a></li><li><a href="module-barejs_polyfill.EntryStore.html">EntryStore</a></li><li><a href="module-barejs_polyfill.EntryStore.Iterator.html">Iterator</a></li><li><a href="module-barejs_polyfill.Function.html">Function</a></li><li><a href="module-barejs_polyfill.Map.html">Map</a></li><li><a href="module-barejs_polyfill.Map-MapIterator.html">MapIterator</a></li><li><a href="module-barejs_polyfill.Math.html">Math</a></li><li><a href="module-barejs_polyfill.Number.html">Number</a></li><li><a href="module-barejs_polyfill.Object.html">Object</a></li><li><a href="module-barejs_polyfill.Promise.html">Promise</a></li><li><a href="module-barejs_polyfill.Set.html">Set</a></li><li><a href="module-barejs_polyfill.Set-SetIterator.html">SetIterator</a></li><li><a href="module-barejs_polyfill.String.html">String</a></li><li><a href="module-barejs_polyfill.Symbol.html">Symbol</a></li><li><a href="module-barejs_polyfill.WeakMap.html">WeakMap</a></li><li><a href="module-barejs_polyfill.WeakSet.html">WeakSet</a></li><li><a href="module-barejs_polyfill_Intl.DateTimeFormat.html">DateTimeFormat</a></li><li><a href="module-barejs_polyfill_Intl.DateTimeFormat-DateTimeFormatOptions.html">DateTimeFormatOptions</a></li><li><a href="module-barejs_polyfill_Intl.NumberFormat.html">NumberFormat</a></li><li><a href="module-barejs_polyfill_Intl.NumberFormat-NumberFormatOptions.html">NumberFormatOptions</a></li><li><a href="module-barejs_polyfill_Intl-Format.html">Format</a></li></ul>
  418. </nav>
  419. <br class="clear">
  420. <footer>
  421. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Wed Oct 03 2018 15:59:34 GMT+0200 (W. Europe Daylight Time)
  422. </footer>
  423. <script> prettyPrint(); </script>
  424. <script src="scripts/linenumber.js"> </script>
  425. </body>
  426. </html>