【问题标题】:Queuing promises排队承诺
【发布时间】:2014-03-14 23:44:40
【问题描述】:

我使用mbostock/queue 来排队一些异步操作。更多的是速率限制(UI 生成的事件很少,后端可以缓慢地处理它),并确保它们按顺序处理。我喜欢用它

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

谢谢。

【问题讨论】:

  • 好问题顺便说一句。我将在接下来的一个小时内继续编辑我的答案/笔,希望我的笔能在以后帮助大家。

标签: javascript angularjs queue q


【解决方案1】:

基本的 $q 链示例

是的,你可以使用 Angular 的 $q! 构建一个链式队列!这是一个示例,向您展示如何使用递归来创建任意长度的队列。每个帖子都是连续发生的(一个接一个)。在第一个帖子完成之前,第二个帖子不会开始。

这在写入数据库时​​会很有帮助。如果数据库后端没有自己的队列,而你同时进行多次写入,你可能会发现你的数据并没有全部保存!

我添加了一个Plunkr example 来演示此代码的运行情况。

$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();
};

您可以使用一个简单的函数来开始您的队列。为了演示,我将一个充满键的对象传递给一个函数,该函数将这些键拆分为单独的帖子,然后将它们发布到Henry's HTTP Post Dumping Server。 (感谢Henry!)

$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 example 的链接。

【讨论】:

    【解决方案2】:

    简短的回答是否定的,您不需要额外的库。 Promise.then() 足够“原子”。长答案是:值得制作一个 queue() 函数来保持代码干燥。 Bluebird-promises 看起来很完整,但这里有一些基于 AngularJS 的 $q 的东西。

    如果我正在制作 .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'); });
    

    【讨论】:

      【解决方案3】:

      链式承诺

      Angular 的$q 实现允许您链接承诺,然后根据您自己的逻辑处理这些承诺的解析。这些方法与mbostock/queue 有点不同,但意图是相同的。创建一个函数来确定您的 defered 将如何被解决(创建一个承诺),然后将它们提供给更高级别的控制器/服务以进行特定的解决方案处理。

      Angular 使用$q.defer() 返回promise 对象,然后可以在应用程序逻辑中按照您希望的顺序调用它们。 (甚至跳过、变异、拦截等)。

      我会写一些代码,但我发现 egghead.io 上的这个 7 分钟视频是最好的简短演示:https://egghead.io/lessons/angularjs-chained-promises,它会更好地解释。 Thomas(演示者)构建了一个非常小的航班仪表板应​​用程序,该应用程序将天气和航班数据排队,并在用户查询他们的行程时处理该队列。 ThomasBurleson/angularjs-FlightDashboard

      我将在 codepen 上设置一个较小的演示,使用“在餐厅吃饭”的情况来演示这个概念:http://codepen.io/LongLiveCHIEF/pen/uLyHx

      此处的代码示例:

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

      【讨论】:

      • 我的“小型”演示正在迅速演变为基于 Promise 架构的教程/示例应用程序。
      • 抱歉,当时不是。我认为那是在 Egghead 制定专业计划之前。
      • 我认为在现场公开视频需要注册和付费的专业帐户是不好的。
      • 3 年前我离开这个答案时,它不是付费内容。但无论如何感谢您的反对!
      猜你喜欢
      • 1970-01-01
      • 2018-11-28
      • 2014-12-29
      • 2018-11-03
      • 1970-01-01
      • 2015-02-18
      • 1970-01-01
      • 2017-10-22
      • 2021-02-24
      相关资源
      最近更新 更多