238 lines
5.6 KiB
JavaScript
238 lines
5.6 KiB
JavaScript
/**
|
||
*
|
||
* @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
|
||
|
||
|
||
})
|
JavaScript
95.2%
CSS
4.8%