224 lines
5.8 KiB
JavaScript
224 lines
5.8 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%