/** * * @authors yutent (yutent@doui.cc) * @date 2016-11-26 16:35:45 * */ "use strict"; define(function(){ var _Promise = function(callback){ this.callback = [] var _this = this if(typeof this !== 'object') throw new TypeError('Promises must be constructed via new') if(typeof callback !== 'function') throw new TypeError('Argument must be a function') callback(function(val){ _resolve(_this, val) }, function(val){ _reject(_this, val) }) } var self = { _state: 1, _fired: 1, _val: 1, callback: 1 } _Promise.prototype = { constructor: _Promise, _state: 'pending', _fired: false, _fire: function(yes, no){ if(this._state === 'rejected'){ if(typeof no === 'function') no(this._val) else throw this._val }else{ if(typeof yes === 'function') yes(this._val) } }, _then: function(yes, no){ if(this._fired){ var _this = this fireCallback(_this, function(){ _this._fire(yes, no) }) }else{ this.callback.push({yes: yes, no: no}) } }, then: function(yes, no){ yes = typeof yes === 'function' ? yes : _yes no = typeof no === 'function' ? no : _no var _this = this var next = new _Promise(function(resolve, reject){ _this._then(function(val){ try{ val = yes(val) }catch(err){ return reject(err) } }, function(val){ try{ val = no(val) }catch(err){ return reject(err) } resolve(val) }) }) for(var i in _this){ if(!self[i]) next[i] = _this[i] } return next }, done: done, catch: fail, fail: fail } _Promise.all = function(arr){ return _some(false, arr) } _Promise.race = function(arr){ return _some(true, arr) } _Promise.defer = defer // ----------------------------------------------------------- function _yes(val){ return val } function _no(err){ throw err } function done(callback){ return this.then(callback, _no) } function fail(callback){ return this.then(_yes, callback) } function defer(){ var obj = {} obj.promise = new this(function(yes, no){ obj.resolve = yes obj.reject = no }) return obj } //成功的回调 function _resolve(obj, val){ if(obj._state !== 'pending') return if(val && typeof val.then === 'function'){ var method = val instanceof _Promise ? '_then' : 'then' val[method](function(v){ _transmit(obj, v, true) }, function(v){ _transmit(obj, v, false) }) }else{ _transmit(obj, val, true) } } //失败的回调 function _reject(obj, val){ if(obj._state !== 'pending') return _transmit(obj, val, false) } // 改变Promise的_fired值,并保持用户传参,触发所有回调 function _transmit(obj, val, isResolved){ obj._fired = true obj._val = val obj._state = isResolved ? 'fulfilled' : 'rejected' fireCallback(obj, function(){ for(var i in obj.callback){ obj._fire(obj.callback[i].yes, obj.callback[i].no) } }) } function fireCallback(obj, callback){ var isAsync = false if(typeof obj.async === 'boolean') isAsync = obj.async else isAsync = obj.async = true if(isAsync) setTimeout(callback, 0) else callback() } function _some(bool, iterable){ iterable = Array.isArray(iterable) ? iterable : [] var n = 0 var res = [] var end = false return new _Promise(function(yes, no){ if(!iterable.length) no(res) function loop(obj, idx){ obj.then(function(val){ if(!end){ res[idx] = val n++ if(bool || n >= iterable.length){ yes(bool ? val : res) end = true } } }, function(val){ end = true no(val) }) } for(var i = 0, len = iterable.length; i < len; i++){ loop(iterable[i], i) } }) } // --------------------------------------------------------------- var nativePromise = window.Promise if(/native code/.test(nativePromise)){ nativePromise.prototype.done = done nativePromise.prototype.fail = fail if(!nativePromise.defer) nativePromise.defer = defer } return window.Promise = nativePromise || _Promise })