| /*! Native Promise Only | |
| v0.8.1 (c) Kyle Simpson | |
| MIT License: http://getify.mit-license.org | |
| */ | |
| (function UMD(name,context,definition){ | |
| // special form of UMD for polyfilling across evironments | |
| context[name] = context[name] || definition(); | |
| if (typeof module != "undefined" && module.exports) { module.exports = context[name]; } | |
| else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); } | |
| })("Promise",typeof global != "undefined" ? global : this,function DEF(){ | |
| /*jshint validthis:true */ | |
| "use strict"; | |
| var builtInProp, cycle, scheduling_queue, | |
| ToString = Object.prototype.toString, | |
| timer = (typeof setImmediate != "undefined") ? | |
| function timer(fn) { return setImmediate(fn); } : | |
| setTimeout | |
| ; | |
| // dammit, IE8. | |
| try { | |
| Object.defineProperty({},"x",{}); | |
| builtInProp = function builtInProp(obj,name,val,config) { | |
| return Object.defineProperty(obj,name,{ | |
| value: val, | |
| writable: true, | |
| configurable: config !== false | |
| }); | |
| }; | |
| } | |
| catch (err) { | |
| builtInProp = function builtInProp(obj,name,val) { | |
| obj[name] = val; | |
| return obj; | |
| }; | |
| } | |
| // Note: using a queue instead of array for efficiency | |
| scheduling_queue = (function Queue() { | |
| var first, last, item; | |
| function Item(fn,self) { | |
| this.fn = fn; | |
| this.self = self; | |
| this.next = void 0; | |
| } | |
| return { | |
| add: function add(fn,self) { | |
| item = new Item(fn,self); | |
| if (last) { | |
| last.next = item; | |
| } | |
| else { | |
| first = item; | |
| } | |
| last = item; | |
| item = void 0; | |
| }, | |
| drain: function drain() { | |
| var f = first; | |
| first = last = cycle = void 0; | |
| while (f) { | |
| f.fn.call(f.self); | |
| f = f.next; | |
| } | |
| } | |
| }; | |
| })(); | |
| function schedule(fn,self) { | |
| scheduling_queue.add(fn,self); | |
| if (!cycle) { | |
| cycle = timer(scheduling_queue.drain); | |
| } | |
| } | |
| // promise duck typing | |
| function isThenable(o) { | |
| var _then, o_type = typeof o; | |
| if (o != null && | |
| ( | |
| o_type == "object" || o_type == "function" | |
| ) | |
| ) { | |
| _then = o.then; | |
| } | |
| return typeof _then == "function" ? _then : false; | |
| } | |
| function notify() { | |
| for (var i=0; i<this.chain.length; i++) { | |
| notifyIsolated( | |
| this, | |
| (this.state === 1) ? this.chain[i].success : this.chain[i].failure, | |
| this.chain[i] | |
| ); | |
| } | |
| this.chain.length = 0; | |
| } | |
| // NOTE: This is a separate function to isolate | |
| // the `try..catch` so that other code can be | |
| // optimized better | |
| function notifyIsolated(self,cb,chain) { | |
| var ret, _then; | |
| try { | |
| if (cb === false) { | |
| chain.reject(self.msg); | |
| } | |
| else { | |
| if (cb === true) { | |
| ret = self.msg; | |
| } | |
| else { | |
| ret = cb.call(void 0,self.msg); | |
| } | |
| if (ret === chain.promise) { | |
| chain.reject(TypeError("Promise-chain cycle")); | |
| } | |
| else if (_then = isThenable(ret)) { | |
| _then.call(ret,chain.resolve,chain.reject); | |
| } | |
| else { | |
| chain.resolve(ret); | |
| } | |
| } | |
| } | |
| catch (err) { | |
| chain.reject(err); | |
| } | |
| } | |
| function resolve(msg) { | |
| var _then, self = this; | |
| // already triggered? | |
| if (self.triggered) { return; } | |
| self.triggered = true; | |
| // unwrap | |
| if (self.def) { | |
| self = self.def; | |
| } | |
| try { | |
| if (_then = isThenable(msg)) { | |
| schedule(function(){ | |
| var def_wrapper = new MakeDefWrapper(self); | |
| try { | |
| _then.call(msg, | |
| function $resolve$(){ resolve.apply(def_wrapper,arguments); }, | |
| function $reject$(){ reject.apply(def_wrapper,arguments); } | |
| ); | |
| } | |
| catch (err) { | |
| reject.call(def_wrapper,err); | |
| } | |
| }) | |
| } | |
| else { | |
| self.msg = msg; | |
| self.state = 1; | |
| if (self.chain.length > 0) { | |
| schedule(notify,self); | |
| } | |
| } | |
| } | |
| catch (err) { | |
| reject.call(new MakeDefWrapper(self),err); | |
| } | |
| } | |
| function reject(msg) { | |
| var self = this; | |
| // already triggered? | |
| if (self.triggered) { return; } | |
| self.triggered = true; | |
| // unwrap | |
| if (self.def) { | |
| self = self.def; | |
| } | |
| self.msg = msg; | |
| self.state = 2; | |
| if (self.chain.length > 0) { | |
| schedule(notify,self); | |
| } | |
| } | |
| function iteratePromises(Constructor,arr,resolver,rejecter) { | |
| for (var idx=0; idx<arr.length; idx++) { | |
| (function IIFE(idx){ | |
| Constructor.resolve(arr[idx]) | |
| .then( | |
| function $resolver$(msg){ | |
| resolver(idx,msg); | |
| }, | |
| rejecter | |
| ); | |
| })(idx); | |
| } | |
| } | |
| function MakeDefWrapper(self) { | |
| this.def = self; | |
| this.triggered = false; | |
| } | |
| function MakeDef(self) { | |
| this.promise = self; | |
| this.state = 0; | |
| this.triggered = false; | |
| this.chain = []; | |
| this.msg = void 0; | |
| } | |
| function Promise(executor) { | |
| if (typeof executor != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| if (this.__NPO__ !== 0) { | |
| throw TypeError("Not a promise"); | |
| } | |
| // instance shadowing the inherited "brand" | |
| // to signal an already "initialized" promise | |
| this.__NPO__ = 1; | |
| var def = new MakeDef(this); | |
| this["then"] = function then(success,failure) { | |
| var o = { | |
| success: typeof success == "function" ? success : true, | |
| failure: typeof failure == "function" ? failure : false | |
| }; | |
| // Note: `then(..)` itself can be borrowed to be used against | |
| // a different promise constructor for making the chained promise, | |
| // by substituting a different `this` binding. | |
| o.promise = new this.constructor(function extractChain(resolve,reject) { | |
| if (typeof resolve != "function" || typeof reject != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| o.resolve = resolve; | |
| o.reject = reject; | |
| }); | |
| def.chain.push(o); | |
| if (def.state !== 0) { | |
| schedule(notify,def); | |
| } | |
| return o.promise; | |
| }; | |
| this["catch"] = function $catch$(failure) { | |
| return this.then(void 0,failure); | |
| }; | |
| try { | |
| executor.call( | |
| void 0, | |
| function publicResolve(msg){ | |
| resolve.call(def,msg); | |
| }, | |
| function publicReject(msg) { | |
| reject.call(def,msg); | |
| } | |
| ); | |
| } | |
| catch (err) { | |
| reject.call(def,err); | |
| } | |
| } | |
| var PromisePrototype = builtInProp({},"constructor",Promise, | |
| /*configurable=*/false | |
| ); | |
| // Note: Android 4 cannot use `Object.defineProperty(..)` here | |
| Promise.prototype = PromisePrototype; | |
| // built-in "brand" to signal an "uninitialized" promise | |
| builtInProp(PromisePrototype,"__NPO__",0, | |
| /*configurable=*/false | |
| ); | |
| builtInProp(Promise,"resolve",function Promise$resolve(msg) { | |
| var Constructor = this; | |
| // spec mandated checks | |
| // note: best "isPromise" check that's practical for now | |
| if (msg && typeof msg == "object" && msg.__NPO__ === 1) { | |
| return msg; | |
| } | |
| return new Constructor(function executor(resolve,reject){ | |
| if (typeof resolve != "function" || typeof reject != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| resolve(msg); | |
| }); | |
| }); | |
| builtInProp(Promise,"reject",function Promise$reject(msg) { | |
| return new this(function executor(resolve,reject){ | |
| if (typeof resolve != "function" || typeof reject != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| reject(msg); | |
| }); | |
| }); | |
| builtInProp(Promise,"all",function Promise$all(arr) { | |
| var Constructor = this; | |
| // spec mandated checks | |
| if (ToString.call(arr) != "[object Array]") { | |
| return Constructor.reject(TypeError("Not an array")); | |
| } | |
| if (arr.length === 0) { | |
| return Constructor.resolve([]); | |
| } | |
| return new Constructor(function executor(resolve,reject){ | |
| if (typeof resolve != "function" || typeof reject != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| var len = arr.length, msgs = Array(len), count = 0; | |
| iteratePromises(Constructor,arr,function resolver(idx,msg) { | |
| msgs[idx] = msg; | |
| if (++count === len) { | |
| resolve(msgs); | |
| } | |
| },reject); | |
| }); | |
| }); | |
| builtInProp(Promise,"race",function Promise$race(arr) { | |
| var Constructor = this; | |
| // spec mandated checks | |
| if (ToString.call(arr) != "[object Array]") { | |
| return Constructor.reject(TypeError("Not an array")); | |
| } | |
| return new Constructor(function executor(resolve,reject){ | |
| if (typeof resolve != "function" || typeof reject != "function") { | |
| throw TypeError("Not a function"); | |
| } | |
| iteratePromises(Constructor,arr,function resolver(idx,msg){ | |
| resolve(msg); | |
| },reject); | |
| }); | |
| }); | |
| return Promise; | |
| }); |