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

How to execute promises "sync" and not in async way

我调用 getBubblesUserAccess returns json 以特殊方式排序的对象。结果我想 运行 一个 foreach 并获取其他消息,但我想 return 它们在 "order" 中。我知道它会 运行 这些异步,但必须有一种方法可以强制它 "sequential" 执行。 (上面的代码是我最后一次尝试添加延迟...)

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

{  
  "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 是 运行ning 异步的(应该如此),我希望它按照与第一个 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);

AngularJS中的$q服务被描述为"lightweight",因为它只实现了90%的人需要的功能。这使得它的代码量很小 - 代价是无法很容易地处理像您这样的请求。

如果您有选择,请尝试其他选择,例如 bluebird。 Bluebird 提供了一个 reduce() 函数,可以连续执行一系列承诺,并且 return 它们的结果按照请求的顺序排列。它使这项任务变得简单明了,因为您的结果数组将匹配您的数据数组,并且您可以非常轻松地匹配结果。

如果你没有那个选项,有一个标准的(如果不是很简单的话)承诺技术,你可以在其中构建一个你想要承诺的元素数组,然后调用处理函数(returns a Promise) 第一个值(从数组中弹出)。在.finally() handler中,递归调用处理函数,下一个值直到为空(或出错)。

伪代码:

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

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