Очередь обещаний

Я использую mbostock / queue для очередей нескольких асинхронных операций. Это больше для ограничения скорости (пользовательский интерфейс генерирует несколько событий, где сервер может обрабатывать их медленно), а также для обеспечения их последовательной обработки. Я использую это как

function request(d, cb) {
 //some async oper
 add.then(function(){
   cb(null, "finished ")
 })
}

var addQ = queue(1);
addQ.defer(request) //called by few req at higher rates generated by UI

Я уже использую angular.js $q для асинхронной операции. Итак, я должен использовать mbostock/queueили я могу построить очередь из $q (что по духу https://github.com/kriskowal/q)

Благодарю.

3 ответа

Решение

Базовый пример цепочки $q

Да, вы можете создать цепочечную очередь, используя Angular $q! Вот пример, который показывает вам, как вы можете использовать рекурсию для создания очереди любой длины. Каждый пост происходит подряд (один за другим). Второй пост не начнется, пока не закончится первый пост.

Это может быть полезно при записи в базы данных. Если база данных не имеет своей собственной очереди на бэкэнде, и вы делаете несколько записей одновременно, вы можете обнаружить, что не все ваши данные сохранены!

Я добавил пример Plunkr, чтобы продемонстрировать этот код в действии.

$scope.setData = function (data) {

  // This array will hold the n-length queue
  var promiseStack = [];

  // Create a new promise (don't fire it yet)
  function newPromise (key, data) {
    return function () {
      var deferred = $q.defer();

      var postData = {};
      postData[key] = data;

      // Post the the data ($http returns a promise)
      $http.post($scope.postPath, postData)
      .then(function (response) {

        // When the $http promise resolves, we also
        // resolve the queued promise that contains it
        deferred.resolve(response);

      }, function (reason) {
        deferred.reject(reason);
      });

      return deferred.promise;
    };
  }

  // Loop through data creating our queue of promises
  for (var key in data) {
    promiseStack.push(newPromise(key, data[key]));
  }

  // Fire the first promise in the queue
  var fire = function () {

    // If the queue has remaining items...
    return promiseStack.length && 

    // Remove the first promise from the array
    // and execute it 
    promiseStack.shift()()

    // When that promise resolves, fire the next
    // promise in our queue 
    .then(function () {
      return fire();
    });
  };

  // Begin the queue
  return fire();
};

Вы можете использовать простую функцию, чтобы начать свою очередь. Ради этой демонстрации я передаю объект, полный ключей, функции, которая разделит эти ключи на отдельные сообщения, а затем отправит их на HTTP-сервер Генри Post Dumping. (Спасибо, Генри!)

$scope.beginQueue = function () {

  $scope.setData({
    a: 0,
    b: 1,
    /* ... all the other letters of the alphabet ... */
    y: 24,
    z: 25

  }).then(function () {

    console.log('Everything was saved!');

  }).catch(function (reason) {
    console.warn(reason);
  });
};

Вот ссылка на пример Plunkr, если вы хотите попробовать этот код.

Короткий ответ - нет, вам не нужна дополнительная библиотека. Promise.then() достаточно "атомарный". Длинный ответ таков: стоит сделать функцию queue() для сохранения кода DRY. Обещания Bluebird кажутся довольно полными, но вот кое-что, основанное на $q AngularJS.

Если бы я делал.queue(), я бы тоже хотел, чтобы он обрабатывал ошибки.

Вот угловая сервисная фабрика и некоторые варианты использования:

/**
 * Simple promise factory
 */

angular.module('app').factory('P', function($q) {
  var P = $q;

  // Make a promise
  P.then = function(obj) {
    return $q.when(obj);
  };

  // Take a promise.  Queue 'action'.  On 'action' faulure, run 'error' and continue.
  P.queue = function(promise, action, error) {
    return promise.then(action).catch(error);
  };

  // Oook!  Monkey patch .queue() onto a $q promise.
  P.startQueue = function(obj) {
    var promise = $q.when(obj);
    promise.queue = function(action, error) {
      return promise.then(action).catch(error);
    };
    return promise;
  };

  return P;
});

Как это использовать:

.run(function($state, YouReallyNeedJustQorP, $q, P) {

  // Use a $q promise.  Queue actions with P

  // Make a regular old promise
  var myPromise = $q.when('plain old promise');

  // use P to queue an action on myPromise
  P.queue(myPromise, function() { return console.log('myPromise: do something clever'); });

  // use P to queue an action
  P.queue(myPromise, function() {
    throw console.log('myPromise: do something dangerous');
  }, function() { 
    return console.log('myPromise: risks must be taken!');
  });
  // use P to queue an action
  P.queue(myPromise, function() { return console.log('myPromise: never quit'); });


  // Same thing, but make a special promise with P

  var myQueue = P.startQueue(myPromise);

  // use P to queue an action
  myQueue.queue(function() { return console.log('myQueue: do something clever'); });

  // use P to queue an action
  myQueue.queue(function() {
    throw console.log('myQueue: do something hard');
  }, function() { 
    return console.log('myQueue: hard is interesting!');
  });
  // use P to queue an action
  myQueue.queue(function() { return console.log('myQueue: no easy days'); });

Цепные обещания

Радиально-х $q Реализация позволяет вам связывать обещания, а затем обрабатывать их решения в соответствии с вашей собственной логикой. Методы немного отличаются от mbostock/queue, но цель та же. Создайте функцию, которая определяет, как будет разрешен ваш защищенный объект (создавая обещание), а затем сделайте их доступными контроллеру / службе более высокого уровня для конкретной обработки разрешения.

Угловое использование $q.defer() возвращать объекты обещания, которые затем можно вызывать в том порядке, который вы хотите внутри логики вашего приложения. (или даже пропущены, видоизменены, перехвачены и т. д.).

Я скину немного кода, но я нашел это 7-минутное видео на egghead.io лучшим коротким демо: https://egghead.io/lessons/angularjs-chained-promises, и оно будет работать намного лучше объяснения. Томас (ведущий) создает очень маленькое приложение для панели управления полетом, которое ставит в очередь данные о погоде и полете и обрабатывает эти очереди, когда пользователь запрашивает их маршрут. ThomasBurleson/angularjs-FlightDashboard

Я буду организовывать меньшую демонстрацию на codepen, используя ситуацию "еды в ресторане", чтобы продемонстрировать эту концепцию: http://codepen.io/LongLiveCHIEF/pen/uLyHx

Примеры кода здесь:

https://gist.github.com/LongLiveCHIEF/4c5432d1c2fb2fdf937d

Другие вопросы по тегам