如何在AngularJS中编写debounce服务
下划线库提供了一个反Bounce函数,可防止在设定的时间段内多次调用函数。他们的版本使用setTimeout 我们如何在纯AngularJS代码中做到这一点如何在AngularJS中编写debounce服务,angularjs,Angularjs,下划线库提供了一个反Bounce函数,可防止在设定的时间段内多次调用函数。他们的版本使用setTimeout 我们如何在纯AngularJS代码中做到这一点 此外,我们是否可以使用$q样式的承诺在去盎司周期后从被调用函数检索返回值?下面是此类服务的一个工作示例:。 它创建了一个$q延迟对象,该对象将在最终调用取消公告函数时解析 每次调用debounce函数时,都会返回对内部函数下一次调用的承诺 // Create an AngularJS service called debounce app.
此外,我们是否可以使用$q样式的承诺在去盎司周期后从被调用函数检索返回值?下面是此类服务的一个工作示例:。 它创建了一个
$q
延迟对象,该对象将在最终调用取消公告函数时解析
每次调用debounce
函数时,都会返回对内部函数下一次调用的承诺
// Create an AngularJS service called debounce
app.factory('debounce', ['$timeout','$q', function($timeout, $q) {
// The service is actually this function, which we call with the func
// that should be debounced and how long to wait in between calls
return function debounce(func, wait, immediate) {
var timeout;
// Create a deferred object that will be resolved when we need to
// actually call the func
var deferred = $q.defer();
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if(!immediate) {
deferred.resolve(func.apply(context, args));
deferred = $q.defer();
}
};
var callNow = immediate && !timeout;
if ( timeout ) {
$timeout.cancel(timeout);
}
timeout = $timeout(later, wait);
if (callNow) {
deferred.resolve(func.apply(context,args));
deferred = $q.defer();
}
return deferred.promise;
};
};
}]);
通过使用promise上的then方法,可以从debounced函数获得返回值
$scope.addMsg = function(msg) {
console.log('addMsg called with', msg);
return msg;
};
$scope.addMsgDebounced = debounce($scope.addMsg, 2000, false);
$scope.logReturn = function(msg) {
console.log('logReturn called with', msg);
var promise = $scope.addMsgDebounced(msg);
promise.then(function(msg) {
console.log('Promise resolved with', msg);
});
};
如果您连续多次快速呼叫
logReturn
,您将看到logReturn
呼叫被一遍又一遍地记录,但只有一个addMsg
呼叫被记录。自从我写了上面的评论之后,我对这一点有了一些改变
简单的回答是,不需要对返回值的函数进行去抖动
为什么??好吧,从哲学上讲,我认为为事件而保持去Boung更有意义,而且只为事件而去Boung。如果你有一个方法返回一个你想去抖动的值,你应该去抖动导致你的方法向下游运行的事件。
用法:
app.directive('autosavable', function(debounce) {
return {
restrict : 'A',
require : '?ngModel',
link : function(scope, element, attrs, ngModel) {
var debounced = debounce(function() {
scope.$broadcast('autoSave');
}, 5000, false);
element.bind('keypress', function(e) {
debounced();
});
}
};
});
Pete BD为debounce服务提供了一个良好的开端,但是,我发现了两个问题:
.directive('remoteValidator', ['$http', 'reactService', function ($http, reactService) {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
var newDebounce = new reactService.Debounce();
var work = function(){
//....
};
elm.on('blur keyup change', function () {
newDebounce.Invoke(function(){ scope.$apply(work); }, 1000, false);
});
}
};
}])
debounce服务和指令都有很好的实现,可以在以下位置与任何ng模型一起工作: 或者只需使用以下方式安装:
bower install ng-debounce
如果您处理的是模型交互,那么angularjs#1.3.0.beta6中已经提供了对此的支持 Angular 1.3标准配置为去盎司 值得一提的是,debounce内置了Angular 1.3。正如您所期望的,它是作为指令实现的。您可以这样做:
<input ng-model='address' ng-model-options="{ debounce: 500 }" />
$scope.address属性直到最后一次击键500毫秒后才会更新
如果你需要更多的控制
如果需要更高的粒度,可以为不同的事件设置不同的反弹时间:
<input ng-model='person.address' ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" />
例如,在这里,我们有一个500毫秒的去抖动用于击键,而没有去抖动用于模糊
文档
阅读此处的文档:旁注:您很可能会问这个问题,因为您有太多的请求,而您只想触发一个请求。在过去的3天里,我一直面临着这个问题,经过十几次重新构造代码和阅读文档的尝试,我在不强制设置超时的情况下实现了我想要的。我在这里概括一下,但看看你是否能以同样的方式处理你的问题。非常神秘的评论!我很想看看你有什么想法。我同意这不应该仅仅用来对付太多的观察者太频繁地开火。这实际上不是我的问题,而是一个被放在邮件列表中的问题。我认为它可能有用的地方是,由于用户的输入,比如在服务器上异步查找以自动完成输入框。您可能只希望在用户停止键入一段时间后才进行查找。出于好奇,您是否发现返回的承诺有任何用途?例如,在自动完成的情况下,最好有一个承诺来告诉我用户最终键入的内容,而不是每次击键的承诺。我开始觉得你可以逃避承诺,也可以逃避去Bouncing+回调,但不能两者兼而有之。事实上,这不是去Bouncing服务中的一个bug。它在每次调用时返回相同的承诺,直到超时完成。问题在于,添加消息(已记录)在每次调用时都会根据相同的承诺一次又一次地调用then。因此,当单个承诺解决时,大量的处理程序正在运行。下面是一个更好的演示,它跟踪承诺,并且每个承诺只添加一个处理程序:严格来说,每个解析都返回相同的承诺。因此,您可以在每次解决之间接受第一个、中间或最后一个承诺。最后一行有一个拼写错误:});应该是}]);除非我错过了什么。。。为我工作,谢谢你!另外,
返回的
需要在调用之前被调用。然后()
我同意Roy的观点,这是一个很好的观点;我使用了这个解决方案,并使用了下划线的debounceIt,似乎您不需要$q依赖项here@AndreyKouznetsov同意-cp来自Pete BD版本,修改后的代码-感谢你的回答似乎是对工厂的误解。工厂返回服务,因此在Pete的回答中,timeout变量在服务内部,就像您的一样。@m59文档:“服务配方生成服务,就像值或工厂配方一样,但它通过使用新运算符调用构造函数来实现。”Pete BD version您会得到一个缓存值,如文档中所述。@LeblancMeneses您对这个问题的看法是正确的,但不是解决方案。这两种方法都产生单例,因此每次使用相同的实例。这些文档是指第一次创建服务的方式。从那时起,将使用相同的实例。您不能以这种方式取消按钮单击的抖动。假设我想单击一个按钮来增加模型上的某个值,每次单击都是+N,然后对模型进行去盎司保存。@VladimirPrudnik
<input ng-model='person.address' ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" />