javascript 如何正确 debounce ajax 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23493726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly debounce ajax requests
提问by Gandalf StormCrow
I have a checkbox than can toggle certain behaviour, however if someone makes a 100 consecutive clicks I don't want to send 100 requests to my server side.
我有一个复选框可以切换某些行为,但是如果有人连续点击 100 次,我不想向我的服务器端发送 100 个请求。
This is what I got in place so far (found this code snippet):
这是我到目前为止所得到的(找到了这个代码片段):
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); };
};
In my document ready function :
在我的文档准备功能中:
deBouncer(jQuery,'smartoggle', 'click', 1500);
Then the event itself :
然后事件本身:
$(window).smartoggle(function(e){
MyToggleFunction();
});
This works as I've put 1500 ms to be the debouncing period, so if you click n times withing 1500 ms it will send only the latest state to the server.
这是有效的,因为我将 1500 毫秒作为去抖动周期,因此如果您在 1500 毫秒内单击 n 次,它将仅将最新状态发送到服务器。
There is however side effect of using this, now my click event for other stuff is messed up. Am I doing something wrong here? Is there a better way to debounce?
然而,使用它有副作用,现在我的其他东西的点击事件被搞砸了。我在这里做错了吗?有没有更好的去抖动方法?
采纳答案by phuzi
Not sure if there can be a "proper" way to do this.
不确定是否有“正确”的方法来做到这一点。
Having said that underscore has such a utility that will create a debounced version of your function...
话虽如此,下划线具有这样一个实用程序,可以创建您的函数的去抖动版本......
var MyToggleDebounced = _.debounce(MyToggleFunction, 1500);
then use MyToggleDebounced
in your click handler.
然后MyToggleDebounced
在您的点击处理程序中使用。
Link to debounce docs on underscorejs
链接到 underscorejs 上的 debounce 文档
Take a look at the annotated source for how they do it.
查看带注释的源代码,了解他们是如何做到的。
回答by plalx
Just debounce the function that does the actual work and I wouldn't load an entire library for this.
只需对执行实际工作的函数进行去抖动,我就不会为此加载整个库。
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'));
}
回答by Gherman
I think that this question is better than it seems first. There is a caveat in how Http Ajax requests work. If you set the delay to 1500ms and you can guarantee that each request is served under this time span than other answers will work just fine. However if any request gets significantly slow it then the requests may come out of order. If that happens, the last processed request is the one for which data will be displayed, not the last sent.
我认为这个问题比最初看起来要好。Http Ajax 请求的工作方式有一个警告。如果您将延迟设置为 1500 毫秒,并且您可以保证在此时间跨度内为每个请求提供服务,那么其他答案就可以正常工作。但是,如果任何请求变得明显缓慢,那么请求可能会出现乱序。如果发生这种情况,最后处理的请求将显示数据,而不是最后发送的请求。
I wrote this class to avoid this caveat (in Typescript, but you should be able to read it):
我写了这个类来避免这个警告(在 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);
};
}
}
This will prevent two ajax-requests processed at the same time and this will send another request if there is a pending one.
这将防止同时处理两个 ajax 请求,如果有待处理的请求,这将发送另一个请求。