如何执行承诺"同步"而不是以异步的方式

时间:2015-09-14 18:58:42

标签: angularjs promise q

我调用getBubblesUserAccess,返回以特殊方式排序的json对象。这样的结果我想要运行一个foreach并获得其他消息,但我想在" order"中返回它们。我知道它将运行这些异步,但必须有一种方法,我可以强制它'#34;顺序"执行。 (上面的代码是我最后一次尝试添加推迟...)

示例 伪代码 - 获取我的群组

{  
  "id":"016cd1fc-89a3-4e4a-9e6e-a102df1b03d9",
  "parent":"53750396-7d26-41f3-913d-1b93276b9e09",
  "name":"XX",
  "createdBy":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
  "hasWriteAccess":true,
  "hasCreateAccess":false,
  "hasDeleteAccess":false,
  "hasAdminAccess":false,
  "settingsBubbleId":"00000000-0000-0000-0000-000000000000"
},
{  
  "id":"016cd1fc-89a3-4e4a-9e6e-a102df1b03d9",
  "parent":"53750396-7d26-41f3-913d-1b93276b9e09",
  "name":"XX",
  "createdBy":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
  "hasWriteAccess":true,
  "hasCreateAccess":false,
  "hasDeleteAccess":false,
  "hasAdminAccess":false,
  "settingsBubbleId":"00000000-0000-0000-0000-000000000000"
}

从这个结果我想迭代那些父id字符串并调用另一个响应这个的服务。

伪代码 对于上面的每个组,使用父ID调用另一个服务并获取结果。此结果将添加到新的JSON对象中。

"messages":[  
  {  
     "id":"f1d1aeda-d4e2-4563-85d5-d954c335b31c",
     "text":"asd",
     "sent":"2015-09-10T22:31:09.897+00:00",
     "sender":"6b9e404b-ef37-4d07-9267-3e7b2579003b",
     "senderName":"XXX XXXX"
  },
  {  
     "id":"a7ac0432-e945-440e-91ce-185170cbf3de",
     "text":"asd",
     "sent":"2015-09-10T22:28:24.383+00:00",
     "sender":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
     "senderName":"ZZZZZ ZZZZ"
  },

我的问题是我的第二个foreach正在运行异步(应该如此),我希望它以与第一个json对象相同的顺序解析...

我的代码::

var loadBubblesAccess = function () {
        if (vm.running && angular.isDefined(vm.running)) { return; }
        vm.running = true;
        vm.bubblesWithMessages = null;

        return BubbleFactory.getBubblesUserAccess().then(function (bubblesAccessTo) {
            return bubblesAccessTo;
        });
    },
        loadSubBubbles = function (bubblesAccessTo) {

            /**
             * Result from chain method with all bubbles user has access to.
             */

            var promiseArray = [];
            //var promiseArrayError = [];
            var i = 0;
            /**
             * Creates a defer object so that we will not resolve before for each loop has been gone thru.. async problems.
             */
            var deferred = $q.defer();

            angular.forEach(bubblesAccessTo, function (bubble) {
                $log.error(JSON.stringify(bubblesAccessTo));
                /**
                 * Get 20 because default thats default and cache and e-tags are done to that number..
                 */
                BubbleFactory.getBubbleMessages(bubble.id, 0, 20, false).then(function (data) {
                        i++;
                        if (data.messages.length > 0) {
                            promiseArray.push({ bubbleSortOrder: i, bubbleId: bubble.parent, bubbleName: bubble.name, bubbleMessagesId: bubble.id, bubbleMessages: smartTrim(data.messages[0].text, 400, ' ', ' ...'), bubbleMessagesSent: data.messages[0].sent });
                        }
                        else {
                            // console.log("YYYY::: " + bubble.parent);
                            promiseArray.push({ bubbleSortOrder:i, bubbleId: bubble.parent, bubbleName: bubble.name, bubbleMessagesId: bubble.id, bubbleMessages: 'Inget meddelande än..', bubbleMessagesSent: '' });
                        }

                    });

                    /**
                     * Check if we have gone thru all bubbles - when finished we resolve defer object.
                     */
                    if(i===bubblesAccessTo.length)
                    {
                        deferred.resolve(promiseArray);
                    }

            });
            //$log.debug.log(promiseArray);
            vm.bubblesWithMessages = promiseArray;
            promiseArray.length = 0;
            vm.running = false;
        };



    loadBubblesAccess().then(loadSubBubbles);

1 个答案:

答案 0 :(得分:2)

AngularJS中的$q服务被描述为“轻量级”,因为它只实现了90%的人需要的功能。这样可以减小代码大小 - 代价是无法轻松解决像你这样的请求。

如果您有选项,请尝试使用bluebird等替代方案。 Bluebird提供了一个reduce()函数,可以按顺序执行一系列promise,并按照请求的顺序返回结果。它使这项任务变得简单,因为您的结果数组将与您的数据数组匹配,您可以非常轻松地匹配结果。

如果你没有那个选项,那么有一个标准的(如果不是非常简单的)技术,你可以构建一个你希望承诺的元素数组,然后调用处理函数(返回一个Promise)在第一个值(从数组中弹出)。在.finally()处理程序中,使用下一个值递归调用处理函数,直到它为空(或发生错误)。

伪代码:

var valuesToProcess = [1, 2, 3],
    results = [];

function processValue(val) {
    myProcessingFunction(val).then(function(result) {
        results.push(result);
    }).catch(function(e) {
        console.log('FAIL!', e);
    }).finally(function() {
        if (valuesToProcess.length > 0) {
            processValue(valuesToProcess.shift());
        } else {
            // All done - do something with results here
        }
    });
}

// Note: No error checking done, assumes we have work to do...
processValue(valuesToProcess.shift());

您需要根据用例进行调整,但这是一种保证串行操作和结果处理的简单技术。