1/** 2@license 3Copyright (c) 2016 The Polymer Project Authors. All rights reserved. 4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 7Code distributed by Google as part of the polymer project is also 8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 9*/ 10function MakePromise (asap) { 11 function Promise(fn) { 12 if (typeof this !== 'object' || typeof fn !== 'function') throw new TypeError(); 13 this._state = null; 14 this._value = null; 15 this._deferreds = [] 16 17 doResolve(fn, resolve.bind(this), reject.bind(this)); 18 } 19 20 function handle(deferred) { 21 var me = this; 22 if (this._state === null) { 23 this._deferreds.push(deferred); 24 return 25 } 26 asap(function() { 27 var cb = me._state ? deferred.onFulfilled : deferred.onRejected 28 if (typeof cb !== 'function') { 29 (me._state ? deferred.resolve : deferred.reject)(me._value); 30 return; 31 } 32 var ret; 33 try { 34 ret = cb(me._value); 35 } 36 catch (e) { 37 deferred.reject(e); 38 return; 39 } 40 deferred.resolve(ret); 41 }) 42 } 43 44 function resolve(newValue) { 45 try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 46 if (newValue === this) throw new TypeError(); 47 if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { 48 var then = newValue.then; 49 if (typeof then === 'function') { 50 doResolve(then.bind(newValue), resolve.bind(this), reject.bind(this)); 51 return; 52 } 53 } 54 this._state = true; 55 this._value = newValue; 56 finale.call(this); 57 } catch (e) { reject.call(this, e); } 58 } 59 60 function reject(newValue) { 61 this._state = false; 62 this._value = newValue; 63 finale.call(this); 64 } 65 66 function finale() { 67 for (var i = 0, len = this._deferreds.length; i < len; i++) { 68 handle.call(this, this._deferreds[i]); 69 } 70 this._deferreds = null; 71 } 72 73 /** 74 * Take a potentially misbehaving resolver function and make sure 75 * onFulfilled and onRejected are only called once. 76 * 77 * Makes no guarantees about asynchrony. 78 */ 79 function doResolve(fn, onFulfilled, onRejected) { 80 var done = false; 81 try { 82 fn(function (value) { 83 if (done) return; 84 done = true; 85 onFulfilled(value); 86 }, function (reason) { 87 if (done) return; 88 done = true; 89 onRejected(reason); 90 }) 91 } catch (ex) { 92 if (done) return; 93 done = true; 94 onRejected(ex); 95 } 96 } 97 98 Promise.prototype['catch'] = function (onRejected) { 99 return this.then(null, onRejected); 100 }; 101 102 Promise.prototype.then = function(onFulfilled, onRejected) { 103 var me = this; 104 return new Promise(function(resolve, reject) { 105 handle.call(me, { 106 onFulfilled: onFulfilled, 107 onRejected: onRejected, 108 resolve: resolve, 109 reject: reject 110 }); 111 }) 112 }; 113 114 Promise.resolve = function (value) { 115 if (value && typeof value === 'object' && value.constructor === Promise) { 116 return value; 117 } 118 119 return new Promise(function (resolve) { 120 resolve(value); 121 }); 122 }; 123 124 Promise.reject = function (value) { 125 return new Promise(function (resolve, reject) { 126 reject(value); 127 }); 128 }; 129 130 131 return Promise; 132} 133 134if (typeof module !== 'undefined') { 135 module.exports = MakePromise; 136} 137 138