$q承诺麻烦



我正在开发一种实用程序服务,用于处理角度中的SharePoint项目。我正在更新我的代码以使用异步的角度承诺。通信而不是回调函数,所以请原谅我的代码在过渡过程中有点混乱。我编写了一些代码来更新单个列表项,然后反复使用该函数来批量更新多个项。代码正在工作,http 请求正在更改我列表中的项目,但我似乎无法承诺在更新多个项目时冒泡回顶部。这是我的代码:

this.UpdateListItem = function (webUrl, listName, itemId, itemProperties, success, failure) {
    if (typeof lists[listName] === 'undefined') {
        lists[listName] = [];
    }
    var deferred = $q.defer();
    var post = angular.copy(itemProperties);
    DataUtilitySvc.ConvertDatesJson(post);
    this.GetListItemById(webUrl, listName, itemId)
        .then(function (item) {
            $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 SuccessCB(response) {
                var temp = [];
                temp.push(itemProperties);
                DataUtilitySvc.MergeByProperty(lists[listName], temp, 'Id');
                deferred.resolve(response);
            }, function FailureCB(response) {
                this.GetListItems(webUrl, listName);
                deferred.reject(response);
            });
        }, function (error) {
            deferred.reject(error);
        });
    return deferred.promise;
};

this.UpdateListItems = function (webUrl, listName, itemsJson, success, failure) {
    if (numItems == -1) {
        numItems = itemsJson.length;
        c = 0;
        f = 0;
    }
    var promises = [];
    itemsJson.forEach(function (itemProps) {
        var deferred = $q.defer();
        this.UpdateListItem(webUrl, listName, itemProps.Id, itemProps)
            .then(function () {
                c++;
                if (c == numItems && f == 0) {
                    numItems = -1;
                    deferred.resolve(itemsJson[listName]);
                }
            }, function (error) {
                c++; f++;
                if (c == numItems) {
                    numItems = -1;
                    deferred.reject(error);
                }
            });
        promises.push(deferred.promise);
    }, this);
    return $q.all(promises);
};

然后这是我从角度控制器调用服务函数的地方。animateAlert 调用使引导警报出现,然后随着指定的文本消失。

$scope.UpdateListItem = function (webUrl, listName, itemId, itemProperties, success, failure) {
    SPListUtility.UpdateListItem(webUrl, listName, itemId, itemProperties, success, failure)
        // The following then clause works and the animations show as intended
        .then(function success(data) {
            console.log(JSON.stringify(data));
            $scope.animateAlert("myAlert", "alertText", "Operation Successful!", "success");
        }, function failure(error) {
            console.log("Error " + error.status + ": " + error.statusText);
            $scope.animateAlert("myAlert", "alertText", "Error " + error.status + ": " + error.statusText, "danger");
        });
};
$scope.UpdateListItems = function (webUrl, listName, itemsJson, success, failure) {
    SPListUtility.UpdateListItems(webUrl, listName, itemsJson, success, failure)
        // The following section is what never seems to get called. These animations never show up
        .then(function success() {
            $scope.animateAlert("myAlert", "alertText", "Items Saved", "success");
        }, function failure(error) {
            console.log("Error " + error.status + ": " + error.statusText);
            $scope.animateAlert("myAlert", "alertText", "Error " + error.status + ": " + error.statusText, "danger");
        });
};

我认为@Bergi建议我做如下的事情:

this.GetListItemById = function (webUrl, listName, itemId, loading) {
    var url = webUrl + "/_vti_bin/listdata.svc/" + listName + "(" + itemId + ")";
    return $http({
        url: url,
        method: 'GET',
        processData: false,
        headers: { "Accept": "application/json;odata=verbose" },
    }).success(function (data) {
        console.log("This Executes");
        return data.d;
    }).error( function (response) {
        return response;
    });
};

这似乎有点像我想要的。它执行异步调用,但它始终返回包含数据、状态、标头、配置和状态文本的整个成功/然后对象。即使我特别说返回 data.d,它仍然返回整个对象。有人知道我错过了什么吗?

感谢您@Bergi回复。如果请求失败,我想将响应返回给用户。这是我的控制器中的代码:

$scope.GetListItemById = function (webUrl, listName, itemId) {
    SPListUtility.GetListItemById(webUrl, listName, itemId)
        .then(function success(data) {
            console.log(JSON.stringify(data));
            $scope.animateAlert("myAlert", "alertText", "Item: " + data.Title + " loaded", "success");
        }).catch( function failure(error) {
            console.log("Error " + error.status + ": " + error.statusText);
            $scope.animateAlert("myAlert", "alertText", "Error " + error.status + ": " + error.statusText, "danger");
        });
};

这一切都主要用于现在的实验和测试,但我希望这项服务在未来是健壮的。然后似乎适用于存在的项目,但问题是,如果我尝试检索一个不存在的项目并且它抛出 404,那么上面列出的函数在返回时仍然会被调用,而不是像我想要的那样捕获。我可以通过手动返回和 Promise.reject 来更改服务功能,强制它工作,但这是遵循最佳实践吗?

this.GetListItemById = function (webUrl, listName, itemId, loading) {
    var url = webUrl + "/_vti_bin/listdata.svc/" + listName + "(" + itemId + ")";
    //var deferred = $q.defer();
    return $http({
        url: url,
        method: 'GET',
        processData: false,
        headers: { "Accept": "application/json;odata=verbose" },
    }).then(function SuccessCB(response) {
        //console.log(JSON.stringify(response));
        return response.data.d;
    }, function FailureCB(response) {
        return Promise.reject(response);
    });
    //return deferred.promise;
};

最新更新