下划线库提供去抖功能,可防止在设定的时间段内对函数进行多次调用.他们的版本使用了setTimeout.
我们怎样才能在纯AngularJS代码中执行此操作?
此外,我们可以利用$ q样式的承诺在去抖期后从被调用的函数中检索返回值吗?
Pet*_* BD 90
以下是此类服务的工作示例:http://plnkr.co/edit/fJwRER?p = preview.它创建了一个$q延迟对象,在最终调用debounced函数时将解析该对象.
每次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;
};
};
}]);
Run Code Online (Sandbox Code Playgroud)
您可以通过在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);
});
};
Run Code Online (Sandbox Code Playgroud)
如果您logReturn快速连续多次呼叫,您将看到logReturn一次addMsg又一次地记录呼叫,但只记录了一次呼叫.
sup*_*ary 50
值得一提的是去抖动内置了Angular 1.3.正如您所期望的那样,它是作为指令实现的.你可以这样做:
<input ng-model='address' ng-model-options="{ debounce: 500 }" />
Run Code Online (Sandbox Code Playgroud)
$ scope.address属性直到最后一次击键后500ms才更新.
如果您想要更多粒度,可以为不同的事件设置不同的跳出时间:
<input ng-model='person.address' ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" />
Run Code Online (Sandbox Code Playgroud)
例如,我们对按键进行500毫秒去抖动,对模糊没有去抖动.
阅读此处的文档:https://docs.angularjs.org/api/ng/directive/ngModelOptions
Roy*_*ove 31
自从我写完上面的评论后,我对此有了一点改变.
简短的回答是,你不应该去抖动返回值的函数.
为什么?好吧,从哲学的角度来看,我认为对事件进行辩解更有意义,而且只针对事件.如果你有一个方法可以返回一个你想去抖动的值,那么你应该去掉导致你的方法向下游运行的事件.
Pete BD为去抖服务提供了一个良好的开端,但是,我看到两个问题:
我目前使用的是:
我将工厂更改为服务,因此每个指令都获得了debounce的新实例,也就是超时变量的新实例. - 我没有遇到过1指令需要超时才能超时[]的情况.
.service('reactService', ['$timeout', '$q', function ($timeout, $q) {
this.Debounce = function () {
var timeout;
this.Invoke = function (func, wait, immediate) {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
if (timeout) {
$timeout.cancel(timeout);
}
timeout = $timeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
return this;
}
}]);
Run Code Online (Sandbox Code Playgroud)
在我的angularjs远程验证器中
.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);
});
}
};
}])
Run Code Online (Sandbox Code Playgroud)