【问题标题】:AngularJS: $watch with debounceAngularJS:$watch 与去抖动
【发布时间】:2015-06-28 13:02:44
【问题描述】:

我有以下代表搜索字段的 html:

<input ng-model-options="{ debounce: 500 }" type="text" ng-model="name">

还有下面的js:

$scope.$watch('name', function(newVal, oldVal) {
            if(newVal != oldVal) {
                $scope.pageChanged($scope.sort, $scope.name, $scope.sortDirection);
            }
        });

现在,我的 pageChanged 函数对我的服务器进行 REST 调用,并根据排序和搜索信息(“名称”)返回一个实体列表。假设我的用户想要搜索“Tom”。我想避免我的应用程序进行三个休息调用(name="T"、name="To"、name="Tom")。

我尝试使用 debounce 执行此操作,但似乎 watch 不适用于 debounce,所以我想知道用最少的代码实现此功能的最佳方法是什么?

【问题讨论】:

  • 您是否尝试过仅在 3 个或更多字符时才拨打电话?
  • 你确定你使用的是 angular 1.3+
  • 你的代码没问题,只要确保 Angular 是 1.3.x 版本 plnkr.co/edit/ttIgZCxtgJq5DSmrgCl8?p=preview
  • 啊,我的错,我有一个较旧的凉亭配置,其中角度设置为 1.2。将其设置为 1.3 并更新使我的代码工作。您能否将其移至答案以便我标记它?

标签: javascript angularjs watch


【解决方案1】:

非常有趣的用例!

解决方案:

我从 lodash 的实现中获得灵感,通过在服务中实现 debounce 函数解决了类似的问题(也可以找到 implementation here(@Pete BD 的答案)。

// 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;
    };
  };
}]);

然后我将它包含在包含$watch 的控制器/指令中,然后像这样(使用您的代码)进行魔术:

$scope.$watch('name', debounce(function(newVal, oldVal) {
   if(newVal != oldVal) {
     $scope.pageChanged($scope.sort, $scope.name, $scope.sortDirection);
   }
}, 500));

完成!


案例历史:

我也尝试过这样做:

$scope.$watch('name', function(newVal, oldVal) {

   debounce(function() {
     if(newVal != oldVal) {
       $scope.pageChanged($scope.sort, $scope.name, $scope.sortDirection);
     },500)();
});

但不满意,因为手表在 50 毫秒内运行了两次。

【讨论】:

    【解决方案2】:

    你应该使用 ng-change 来处理这种事情,而不是连接手表。

    <input ng-model-options="{ debounce: 500 }" type="text" ng-model="name" ng-change="modelChanged()">
    

    JS:

    var timeout = $timeout(function(){});
    
    $scope.modelChanged = function(){
        $timeout.cancel(timeout); //cancel the last timeout
        timeout = $timeout(function(){
            $scope.pageChanged($scope.sort, $scope.name, $scope.sortDirection);
        }, 500);
    };
    

    我不熟悉 debounce,但它可能会达到同样的效果。

    【讨论】:

    • +1 ! Debounce 只是一个描述你正在做的事情的术语。好的! (那里有很多图书馆 - npmjs.com/search?q=debounce
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 2015-06-28
    相关资源
    最近更新 更多