forked from mirrors/webxoss-core
175 lines
No EOL
4.5 KiB
JavaScript
175 lines
No EOL
4.5 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* 创建一个Callback对象.
|
|
* @class
|
|
* @example
|
|
* 使用Callback实现的计时器:
|
|
* function wait (t) {
|
|
* return new Callback(function (callback) {
|
|
* setTimeout(callback,t*1000);
|
|
* });
|
|
* }
|
|
* @param {Callback~executor} fn - 用于初始化Callback对象的执行函数.
|
|
*/
|
|
|
|
/**
|
|
* 执行函数.
|
|
* @callback Callback~executor
|
|
* @param {function} 操作完成声明函数,该函数被调用后,
|
|
* 由此执行函数创建的Callback对象的状态将变为`Done`,
|
|
* 其回调函数队列将被调用,参数将传入第一个回调函数.
|
|
*/
|
|
function Callback (fn) {
|
|
/**
|
|
* 回调函数队列.
|
|
* @private {function[]}
|
|
*/
|
|
this._callbacks = [];
|
|
|
|
/**
|
|
* 回调函数的上下文对象队列.
|
|
* @private {Object[]}
|
|
*/
|
|
this._thisArray = [];
|
|
|
|
/**
|
|
* Callback的状态.
|
|
* `_done` 为false时表示该Callback处于pending状态.
|
|
* `_done` 为true时表示该Callback处于done状态.
|
|
* @private {boolean}
|
|
*/
|
|
this._done = false;
|
|
|
|
/**
|
|
* 调用首个回调函数时的参数.
|
|
* @private
|
|
*/
|
|
this._arg = [];
|
|
|
|
fn(this._handleCallbacks.bind(this));
|
|
}
|
|
|
|
/**
|
|
* 创建一个永远处于pending状态的Callback.
|
|
* @returns {Callback} 永远处于pending状态的Callback.
|
|
*/
|
|
Callback.never = function () {
|
|
return new Callback(function () {});
|
|
};
|
|
|
|
/**
|
|
* 创建一个立即回调的Callback.
|
|
* 通常用于同步操作和异步操作混合的场合,提供语法糖功能.
|
|
* @returns {Callback} 立即回调的Callback,调用参数会传递到回调函数.
|
|
*/
|
|
Callback.immediately = function () {
|
|
var arg = arguments;
|
|
return new Callback(function (callback) {
|
|
callback.apply(this,arg);
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* 异步的循环`forEach`,语法类似于`Array.prototype.forEach`.
|
|
* @example
|
|
* `arr`为一个数据数组,`doSomethingAsynWith`是一个返回Callback对象的异步处理函数.
|
|
* 现在要遍历`arr`,对每一个元素执行异步处理:
|
|
* Callback.forEach(arr,function (item,index,arr) {
|
|
* return doSomethingAsynWith(item);
|
|
* },this).callback(this,function () {
|
|
* // all done;
|
|
* });
|
|
* @returns {Callback}.
|
|
*/
|
|
Callback.forEach = function (arr,fn,thisp) {
|
|
return arr.reduce(function (chain,item,i,array) {
|
|
return chain.callback(thisp,fn.bind(thisp,item,i,array));
|
|
},Callback.immediately());
|
|
};
|
|
|
|
/**
|
|
* 异步的循环`for`.
|
|
* @example
|
|
* `doSomethingAsyn`是一个返回Callback对象的异步处理函数.
|
|
* 现在循环执行10次`doSomethingAsyn`:
|
|
* Callback.for(this,1,10,function (i) {
|
|
* return doSomethingAsyn(i);
|
|
* },this).callback(this,function () {
|
|
* // all done;
|
|
* });
|
|
* @returns {Callback}.
|
|
*/
|
|
Callback.for = function (thisp,min,max,fn) {
|
|
var chain = Callback.immediately();
|
|
for (var i = min; i <= max; i++) {
|
|
chain.callback(thisp,fn.bind(thisp,i));
|
|
}
|
|
return chain;
|
|
};
|
|
|
|
/**
|
|
* 异步的循环`loop`.
|
|
* @example
|
|
* `doSomethingAsyn`是一个返回Callback对象的异步处理函数.
|
|
* 现在循环执行10次`doSomethingAsyn`:
|
|
* Callback.loop(this,10,function () {
|
|
* return doSomethingAsyn();
|
|
* },this).callback(this,function () {
|
|
* // all done;
|
|
* });
|
|
* @returns {Callback}.
|
|
*/
|
|
Callback.loop = function (thisp,n,fn) {
|
|
var chain = Callback.immediately();
|
|
while (n--) {
|
|
chain.callback(thisp,fn.bind(thisp));
|
|
}
|
|
return chain;
|
|
}
|
|
|
|
/**
|
|
* 处理回调函数队列. 该方法总是在Callback对象的状态变为done时调用.
|
|
* @private
|
|
*/
|
|
Callback.prototype._handleCallbacks = function () {
|
|
this._done = true;
|
|
if (this._callbacks.length) {
|
|
var callback = this._callbacks.shift();
|
|
var thisp = this._thisArray.shift();
|
|
var returnValue = callback.apply(thisp,arguments);
|
|
if (isObj(returnValue) && isFunc(returnValue.callback)) {
|
|
this._done = false;
|
|
returnValue.callback(this,this._handleCallbacks);
|
|
} else {
|
|
this._handleCallbacks(returnValue);
|
|
}
|
|
} else {
|
|
this._arg = arguments;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* 向Callback对象添加回调函数. 可以链式调用.
|
|
* @public
|
|
* @param thisp - 绑定的上下文对象.
|
|
* @param {function} func - 回调函数.
|
|
* 回调函数的返回值为Callback对象时,其后续的回调函数会在Callback的状态变为done时才执行,
|
|
* 否则该回调函数执行后,后续的回调函数立即执行,并把返回值作为参数传入.
|
|
*/
|
|
Callback.prototype.callback = function (thisp,func) {
|
|
if (arguments.length !== 2) {
|
|
debugger;
|
|
console.warn('thisp is not specified!');
|
|
func = thisp;
|
|
thisp = this;
|
|
}
|
|
this._thisArray.push(thisp);
|
|
this._callbacks.push(func);
|
|
if (this._done) this._handleCallbacks.apply(this,this._arg);
|
|
return this;
|
|
};
|
|
|
|
global.Callback = Callback; |