[英]How to properly debounce ajax requests
我有一个复选框可以切换某些行为,但是如果有人连续点击 100 次,我不想向我的服务器端发送 100 个请求。
这是我到目前为止所得到的(找到了这个代码片段):
deBouncer = function($,cf,of, interval){
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
}
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || interval);
}
}
jQuery.fn[cf] = function(fn){ return fn ? this.bind(of, debounce(fn)) : this.trigger(cf); };
};
在我的文档准备功能中:
deBouncer(jQuery,'smartoggle', 'click', 1500);
然后事件本身:
$(window).smartoggle(function(e){
MyToggleFunction();
});
这是有效的,因为我将 1500 毫秒作为去抖动周期,因此如果您在 1500 毫秒内单击 n 次,它将仅将最新状态发送到服务器。
然而,使用它有副作用,现在我的其他东西的点击事件被搞砸了。 我在这里做错了吗? 有没有更好的去抖动方法?
只需对执行实际工作的函数进行去抖动,我就不会为此加载整个库。
var debouncedSomeFunction = debounce(someFunction, 1500); debouncedSomeFunction(); debouncedSomeFunction(); debouncedSomeFunction(); setTimeout(debouncedSomeFunction, 2000); function debounce(fn, bufferInterval) { var timeout; return function () { clearTimeout(timeout); timeout = setTimeout(fn.apply.bind(fn, this, arguments), bufferInterval); }; } function someFunction() { log('someFunction executed'); } function log(text) { document.body.appendChild(document.createTextNode(text)); document.body.appendChild(document.createElement('br')); }
不确定是否有“正确”的方法来做到这一点。
话虽如此,下划线具有这样一个实用程序,可以创建您的函数的去抖动版本......
var MyToggleDebounced = _.debounce(MyToggleFunction, 1500);
然后在您的点击处理程序中使用MyToggleDebounced
。
链接到 underscorejs 上的 debounce 文档
查看带注释的源代码,了解他们是如何做到的。
我认为这个问题比最初看起来要好。 Http Ajax 请求的工作方式有一个警告。 如果您将延迟设置为 1500 毫秒,并且您可以保证在此时间跨度内为每个请求提供服务,那么其他答案就可以正常工作。 但是,如果任何请求变得明显缓慢,那么请求可能会出现问题。 如果发生这种情况,最后处理的请求将显示数据,而不是最后发送的请求。
我写了这个类来避免这个警告(在 Typescript 中,但你应该能够阅读它):
export class AjaxSync {
private isLoading: boolean = false;
private pendingCallback: Function;
private timeout;
public debounce(time: number, callback: Function): Function {
return this.wrapInTimeout(
time,
() => {
if (this.isLoading) {
this.pendingCallback = callback;
return;
}
this.isLoading = true;
callback()
.then(() => {
this.isLoading = false;
if (this.pendingCallback) {
const pendingCallback = this.pendingCallback;
this.pendingCallback = null;
this.debounce(time, pendingCallback);
}
});
}
);
}
private wrapInTimeout(time, callback) {
return () => {
clearTimeout(this.timeout);
this.timeout = setTimeout(callback, time);
};
}
}
这将防止同时处理两个 ajax 请求,如果有一个待处理的请求,这将发送另一个请求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.