$q 对 foreach 的承诺

$q promise with foreach

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

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 在第一个项目 return 成功后立即 returning,而不是等待其余的异步项目调用。非常感谢任何帮助,我对这一切都是陌生的。谢谢!

编辑:按要求添加 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);
        });
};

似乎 this.UpdateListItem 函数已经通过 $promise 对象返回了承诺。这就是为什么你能够对它使用 .then(chain promise) 函数。

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

改为

promises.push(itemPromise)

来自

promises.push(itemPromise.$promise)

这个问题可能与

有点相关