Как написать службу debounce в AngularJS

Библиотека подчеркивания предоставляет функцию debounce, которая предотвращает множественные вызовы функции в течение заданного периода времени. В их версии используется setTimeout.

Как мы можем сделать это в чистом коде AngularJS?

Более того, можем ли мы использовать обещания $ q style для получения возвращаемого значения из вызываемой функции после периода дебюта?

Ниже приведен рабочий пример такой службы: http://plnkr.co/edit/fJwRER?p=preview . Он создает объект с отсрочкой $q который будет разрешен при окончательном вызове функции debounced.

Каждый раз, когда функция debounce называется promiseм следующего вызова внутренней функции, возвращается.

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

Вы получаете возвращаемое значение из функции debounced, используя метод then по обещанию.

 $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 call logReturn снова и снова, но регистрируется только один вызов addMsg .

Угловая 1.3 имеет стандартное отклонение

Стоит упомянуть, что deboub встроен с Angular 1.3. Как и следовало ожидать, это реализовано как директива. Вы можете сделать это:

  

Атрибут $ scope.address не обновляется до 500 мс после последнего нажатия клавиши.

Если вам нужно больше контроля

Если вы хотите увеличить степень детализации, вы можете установить различные времена отказов для разных событий:

  

Здесь, например, у нас есть откат на 500 мкс за нажатие клавиши, и нет отклонений от размытия.

Документация

Читайте документацию здесь: https://docs.angularjs.org/api/ng/directive/ngModelOptions

Поскольку я написал комментарии выше, у меня было немного изменений в этом.

Короткий ответ: вам не нужно отказываться от функций, возвращающих значения.

Зачем? Ну, философски, я думаю, что имеет смысл продолжать дебаты для событий и только для событий. Если у вас есть метод, который возвращает значение, которое вы хотите отменить, вместо этого вы должны отменить событие, которое заставляет ваш метод работать вниз по течению.

Пит БД дал хорошее начало службе дебюта, однако я вижу две проблемы:

  1. возвращается, когда вы должны отправить обратный вызов work (), который использует закрытие javascript, если вам нужно изменить состояние в вызывающем.
  2. timeout variable – не является ли эта переменная таймаутом проблемой? тайм-аут [] может быть? представьте 2 директивы, использующие debounce – signalr, средство проверки формы ввода, я считаю, что заводский подход сломается.

То, что я использую в настоящее время:

Я сменил завод на службу, поэтому каждая директива получает новый экземпляр debounce aka нового экземпляра переменной тайм-аута. – Я не столкнулся с ситуацией, когда 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; } }]); - .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; } }]); 

в моем удаленном валидаторе 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); }); } }; }]) 

Существует хорошая реализация как службы debounce, так и директивы, которая может работать с любой ng-моделью по адресу: https://github.com/shahata/angular-debounce

Или просто установите его, используя:

 bower install ng-debounce 

https://github.com/capaj/ng-tools/blob/master/src/debounce.js

Применение:

 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(); }); } }; }); противодребезговой 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(); }); } }; }); 

Поддержка этого приземлилась в angularjs # 1.3.0.beta6, если вы имеете дело с модельным взаимодействием.

https://docs.angularjs.org/api/ng/directive/ngModelOptions

  • Угловой фильтр точно по объектной клавише
  • Как отменить запрос $ http в AngularJS?
  • При написании директивы в AngularJS, как я могу решить, нужна ли мне новая область, новая область для детей или новая изолированная область?
  • Альтернатива ng-show / -hide или как загрузить только соответствующий раздел DOM
  • Использование ng-if внутри ng-repeat?
  • Использование $ broadcast (), $ emit () и $ on () в AngularJS
  • Почему AngularJS включает в себя пустую опцию?
  • Одностраничное приложение - загрузка js-файла динамически на основе частичного представления
  • Угловые данные JS связаны в ng-bind-html?
  • Как заставить AngularJS связываться с атрибутом title тега A?
  • Как понять «терминал» директивы?
  • Interesting Posts

    Удаленный рабочий стол на ПК с Windows 8.1 с высоким масштабированием DPI

    Автоматизация конфигурации компьютеров Windows без создания образа диска

    Как я могу автоматически сохранять снимки экрана нажатием кнопки Prt Scr?

    Selenium WebDriver выбрасывает исключение в streamе «main» org.openqa.selenium.ElementNotInteractableException

    Как я могу легко разбить CSV на два листа Excel с помощью PowerShell?

    Могу ли я заставить Windows 7 изменять настройки моего прокси-сервера на основе моего сетевого подключения?

    Настроить правила быстрого действия «Лампочки»

    Удаление свойств и личной информации – пакетный режим или приложение

    Как рассчитать среднее значение на основе повторяющихся групп?

    статические файлы с помощью express.js

    Как удалить все пробелы из строки?

    Применение шаблона к документу Word 2013

    Вопрос о прекращении streamа в .NET.

    Что такое наследование конструктора?

    Скрипт Vim, который проверяет заглавные буквы и вносит необходимые исправления

    Давайте будем гением компьютера.