$ q承诺与foreach

时间:2016-03-10 19:07:51

标签: javascript angularjs asynchronous promise angular-promise

我正在编写一个角度服务来处理SharePoint数据,但我遇到了一个问题。我在我的服务中有一个更新和单项的功能,并返回$ http承诺,工作正常。问题是我现在正在尝试编写一个函数,它利用第一个函数来循环和更新多个项目。我希望它在所有项目都已更新后返回单个承诺,并且如果任何正在更新的项目失败,它应该拒绝。这是功能:

this.UpdateListItems = function (webUrl, listName, itemsJson) {
    if (numItems == -1) {
        numItems = itemsJson.length;
        c = 0;
        f = 0;
    }
    var promises = [];

    itemsJson.forEach(function (itemProps) {
        var itemPromise = this.UpdateListItem(webUrl, listName, itemProps.Id, itemProps)
            .then(function (response) {
                c++;
                if (c == numItems && f == 0) {
                    numItems = -1;
                    return itemsJson[listName];
                }
            }, function (error) {
                c++; f++;
                alert("ERROR!");//This gets called first alert below
                if (c == numItems) {
                    numItems = -1;
                    return $q.reject(error);
                }
            });
        promises.push(itemPromise.$promise)
    }, this);
    return $q.all(promises)
        .then(function (data) {
            alert("IN SUCCESS"); //This always gets called immediately after first item success instead of waiting for all items to finish
        }, function (error) {
            alert("IN ERROR"); //This never gets called
        });
};

$ q.all在第一个项成功返回后立即返回,而不是等待其余的异步项调用。非常感谢任何帮助,我是这一切的新手。谢谢!

编辑:按要求添加UpdateListItem代码:

this.UpdateListItem = function (webUrl, listName, itemId, itemProperties) {
    if (typeof lists[listName] === 'undefined') {
        lists[listName] = [];
    }
    var post = angular.copy(itemProperties);
    DataUtilitySvc.ConvertDatesJson(post);
    return this.GetListItemById(webUrl, listName, itemId)
        .then(function (item) {
            return $http({
                url: item.__metadata.uri,
                method: 'POST',
                contentType: 'application/json',
                processData: false,
                headers: {
                    "Accept": "application/json;odata=verbose",
                    "X-HTTP-Method": "MERGE",
                    "If-Match": item.__metadata.etag
                },
                data: JSON.stringify(post),
                dataType: "json",
            }).then(function (response) {
                var temp = [];
                temp.push(itemProperties);
                DataUtilitySvc.MergeByProperty(lists[listName], temp, 'Id');
                return response;
            }, function (error) {
                return $q.reject(error);
            });
        }, function (error) {
            return $q.reject(error);
        });
};

1 个答案:

答案 0 :(得分:3)

似乎this.UpdateListItem函数已经通过$promise对象返回了promise。这就是为什么你能够拥有.then(连锁承诺)功能的原因。

所以基本上你只需要推送返回的itemPromise对象而不是itemPromise.$promise数组中的promises。基本上,当您执行$promise时,它会创建一个[undefined, undefined, ...]数组,并在循环完成后立即解析。

更改为

promises.push(itemPromise)

promises.push(itemPromise.$promise)

这个问题可能与this answer

有关