if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = Deferred;
}
////////////////////////////////////////////////////////////////////////////////
/**
* 2017/2/28
* 定型版
*
* 內核以(jquery樣式)為主
*
*/
////////////////////////////////////////////////////////////////////////////////
function Deferred() {
if (!(this instanceof Deferred)) {
return new Deferred();
}
var SimpleDeferred = Deferred.prototype.core;
return new SimpleDeferred();
}
////////////////////////////////////////////////////////////////////////////////
/**
* Deferred 登錄 class_SimpleDeferred
*/
(function(_self) {
_self.prototype.core = SimpleDeferred;
var PENDING = 1; // 事件仍在處理狀態
var FULFILLED = 2; // 事件已處理完成
var REJECTED = 3; // 事件已處理完,但拋出 reject
////////////////////////////////////////////////////////////////////////////
function SimpleDeferred() {
this.parent = _self;
this.Job = Job;
this.Promise = Promise_;
this.fn = this.constructor;
/* ------------------------ */
this.id = this.fn.id++; // for test
this.value;
this.reason;
this.status = PENDING; // 需要做成 primative
this.jobList = [];
}
SimpleDeferred.id = 0;
////////////////////////////////////////////////////////////////////////////
(function() {
/**
* 註冊 job
*/
this.prototype.then = function(onFulfilled, onRejected) {
var res, self = this;
/* ---------------------------------- */
// check
if (onFulfilled != null && typeof onFulfilled !== 'function') {
throw new TypeError('then.args[0] must be function');
}
if (onRejected != null && typeof onRejected !== 'function') {
throw new TypeError('then.args[1] must be function');
}
/* ---------------------------------- */
if (this.status === PENDING) {
// 若任務尚在執行
var job = new this.Job(onFulfilled, onRejected);
this.jobList.push(job);
} else {
if (this.status === FULFILLED) {
// 任務已經正常結束
(typeof onFulfilled === 'function') && (res = onFulfilled(this.value));
} else {
// 任務已經異常結束
(typeof onRejected === 'function') && (res = onRejected(this.reason));
}
(res instanceof SimpleDeferred) && (self = res);
}
/* ---------------------------------- */
return self;
};
/* ================================================================== */
/**
* 通知執行狀態
*
* @param {boolean} specialCondition: 是否是特殊情況
* 通常已經執行過的的,不能再 resolve()
* 但某些狀況會例外
*
*/
this.prototype.resolve = function(value) {
this.value = value;
/* ------------------------ */
this.status = FULFILLED;
/* ------------------------ */
/**
* 執行註冊過的 job
*/
this._doJob();
return this;
};
/* ================================================================== */
/**
* 通知執行狀態
* @param {boolean} specialCondition: 是否是特殊情況
* 通常已經執行過的的,不能再 reject()
* 但某些狀況會例外
*/
this.prototype.reject = function(reason) {
/* ------------------------ */
if (arguments.length > 1) {
this.reason = [].slice.call(arguments);
} else {
this.reason = reason;
}
/* ------------------------ */
this.status = REJECTED;
/* ------------------------ */
/**
* 執行註冊過的 job
*/
this._doJob();
return this;
};
/* ================================================================== */
this.prototype.done = function(onFulfilled) {
var self = this.then(onFulfilled, undefined);
return self;
};
/* ================================================================== */
this.prototype.catch = function(onRejected) {
var self = this.then(undefined, onRejected);
return self;
};
/* ================================================================== */
this.prototype.fail = function(onRejected) {
var self = this.then(undefined, onRejected);
return self;
};
this.prototype.promise = function() {
var promise = new this.Promise(this);
return promise;
};
}).call(SimpleDeferred);
////////////////////////////////////////////////////////////////////////////
(function() {
/**
* 執行所有註冊的任務
*/
this.prototype._doJob = function() {
/**
* 執行註冊過的 job
*/
while (this.jobList.length) {
// 表示有等待他完成後要執行的工作
var callback, outValue;
var job = this.jobList.shift();
/* ---------------------------------- */
if (this.status === FULFILLED) {
outValue = this.value;
callback = job.getResolve();
} else {
outValue = this.reason;
callback = job.getReject();
}
/* ---------------------------------- */
if (typeof callback !== 'function') {
continue;
}
/* ---------------------------------- */
// 比較麻煩之處
var res = callback(outValue);
/* ---------------------------------- */
if ((res instanceof SimpleDeferred) || (res instanceof this.Promise)) {
if (res instanceof this.Promise) {
res = res.def;
}
// 把責任交出去
res.jobList = res.jobList.concat(this.jobList);
this.jobList = [];
// 檢查 res 的狀態
switch (res.status) {
case PENDING:
/* do nothing,等待他完成事項 */
break;
case FULFILLED:
/**
* 因為 res 已經執行過 resolve
* 所以要把 resolve(value)再傳一遍
*/
res.resolve(res.value);
break;
case REJECTED:
/**
* 因為 res 已經執行過 reject
* 所以要把 reject(reason)再傳一遍
*/
res.reject(res.reason);
break;
default:
break;
}
break;
} else {
continue;
}
/* ---------------------------------- */
}
};
}).call(SimpleDeferred);
////////////////////////////////////////////////////////////////////////////
/**
* 處理 then()
*/
function Job(onFulfilled, onRejected) {
var self = this;
var resolve;
var reject;
__construct();
/**
* 建構式
*/
function __construct() {
(typeof onFulfilled === 'function') && (resolve = onFulfilled);
(typeof onRejected === 'function') && (reject = onRejected);
}
/* ================================================================== */
this.getResolve = function() {
return (typeof resolve === 'function' ? resolve : undefined);
};
/* ================================================================== */
this.getReject = function() {
return (typeof reject === 'function' ? reject : undefined);
};
}
////////////////////////////////////////////////////////////////////////////
/**
* Deferred 的包裹
*/
function Promise_(deferred) {
this.def = deferred;
}
(function() {
this.then = function(onFulfilled, onRejected) {
this.def.then(onFulfilled, onRejected);
return this;
};
this.done = function(onFulfilled) {
this.def.done(onFulfilled);
return this;
};
this.fail = function(onRejected) {
this.def.fail(onRejected);
return this;
};
this.catch = function(onRejected) {
this.def.catch(onRejected);
return this;
};
}).call(Promise_.prototype);
})(Deferred);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
(function(_self) {
/**
* Deferred 類別方法
*
* 只有全部任務完成才能 resolve
* 其中之一拋出 reject 就全 out
*/
_self.all = function(defList) {
if (!Array.isArray(defList)) {
throw new TypeError('arg must be array');
}
var all_def = Deferred();
data = {
self: all_def,
values: [],
reasons: undefined,
count: defList.length
};
/* ---------------------------------- */
// 為每個 deferred 註冊事件
for (var i = 0; i < defList.length; i++) {
data.values[i] = undefined;
var _def = defList[i];
bindEvent_1(_def, data, i);
}
return all_def;
};
function bindEvent_1(_def, data, index) {
var self = data.self;
_def.then(function(value) {
data.values[index] = value;
if (--data.count == 0) {
// defList 都完成
self.resolve(data.values);
}
}, function(reason) {
var values = data.values.slice(0);
self.reject(reason, values);
});
};
/* ====================================================================== */
/**
* Deferred 類別方法
*/
_self.race = function(defList) {
if (!Array.isArray(defList)) {
throw new TypeError('arg must be array');
}
var race_def = Deferred();
data = {
self: race_def,
values: undefined,
reasons: undefined,
count: defList.length
};
/* ---------------------------------- */
// 為每個 deferred 註冊事件
for (var i = 0; i < defList.length; i++) {
data.values[i] = undefined;
var _def = defList[i];
bindEvent_2(_def, data, i);
}
return race_def;
};
function bindEvent_2(_def, data, index) {
var self = data.self;
_def.then(function(value) {
// defList 都完成
self.resolve(values);
}, function(reason) {
self.reject(reason);
});
}
})(Deferred);
////////////////////////////////////////////////////////////////////////////////