define(function () {
var lib = {};
var ORIGIN_METHOD = '\0__throttleOriginMethod';
var RATE = '\0__throttleRate';
/**
* ???? ??????????fn ????????????????
* ???????
* notifyWhenChangesStop
* ???????????????
* ???trailing?true?debounce?true ??
* notifyAtFixRate
* ?????????????
* ???trailing?true?debounce?false ??
* ???
* ??model??view????????throttle?
* ????view??model??????????????????
* ???????model?server???????
*
* @public
* @param {(Function|Array.<Function>)} fn ???????
* ??fn?array?????????????throttle?
* ???????timer?
* @param {number} delay ?????????
* @param {bool} trailing ?????????????
* true?????????????????
* ????????????????delay?
* false??????????????????
* ???????delay??????????
* @param {bool} debounce ??
* true?????????????delay????????
* false?????????????delay??????????
* @return {(Function|Array.<Function>)} ???????
* ????fn?array???????array?
* ???Function?
*/
lib.throttle = function (fn, delay, trailing, debounce) {
var currCall = (new Date()).getTime();
var lastCall = 0;
var lastExec = 0;
var timer = null;
var diff;
var scope;
var args;
var isSingle = typeof fn === 'function';
delay = delay || 0;
if (isSingle) {
return createCallback();
}
else {
var ret = [];
for (var i = 0; i < fn.length; i++) {
ret[i] = createCallback(i);
}
return ret;
}
function createCallback(index) {
function exec() {
lastExec = (new Date()).getTime();
timer = null;
(isSingle ? fn : fn[index]).apply(scope, args || []);
}
var cb = function () {
currCall = (new Date()).getTime();
scope = this;
args = arguments;
diff = currCall - (debounce ? lastCall : lastExec) - delay;
clearTimeout(timer);
if (debounce) {
if (trailing) {
timer = setTimeout(exec, delay);
}
else if (diff >= 0) {
exec();
}
}
else {
if (diff >= 0) {
exec();
}
else if (trailing) {
timer = setTimeout(exec, -diff);
}
}
lastCall = currCall;
};
/**
* Clear throttle.
* @public
*/
cb.clear = function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
return cb;
}
};
/**
* ???????????????????
*
* @public
*/
lib.fixRate = function (fn, delay) {
return delay != null
? lib.throttle(fn, delay, true, false)
: fn;
};
/**
* ????????????????????????
*
* @public
*/
lib.debounce = function (fn, delay) {
return delay != null
? lib.throttle(fn, delay, true, true)
: fn;
};
/**
* Create throttle method or update throttle rate.
*
* @example
* ComponentView.prototype.render = function () {
* ...
* throttle.createOrUpdate(
* this,
* '_dispatchAction',
* this.model.get('throttle'),
* 'fixRate'
* );
* };
* ComponentView.prototype.remove = function () {
* throttle.clear(this, '_dispatchAction');
* };
* ComponentView.prototype.dispose = function () {
* throttle.clear(this, '_dispatchAction');
* };
*
* @public
* @param {Object} obj
* @param {string} fnAttr
* @param {number} rate
* @param {string} throttleType 'fixRate' or 'debounce'
*/
lib.createOrUpdate = function (obj, fnAttr, rate, throttleType) {
var fn = obj[fnAttr];
if (!fn || rate == null || !throttleType) {
return;
}
var originFn = fn[ORIGIN_METHOD] || fn;
var lastRate = fn[RATE];
if (lastRate !== rate) {
fn = obj[fnAttr] = lib[throttleType](originFn, rate);
fn[ORIGIN_METHOD] = originFn;
fn[RATE] = rate;
}
};
/**
* Clear throttle. Example see throttle.createOrUpdate.
*
* @public
* @param {Object} obj
* @param {string} fnAttr
*/
lib.clear = function (obj, fnAttr) {
var fn = obj[fnAttr];
if (fn && fn[ORIGIN_METHOD]) {
obj[fnAttr] = fn[ORIGIN_METHOD];
}
};
return lib;
});
|