【问题标题】:Rethrowing exceptions in nested promise chains重新抛出嵌套承诺链中的异常
【发布时间】:2015-04-02 03:08:21
【问题描述】:

我正在尝试找出一种在 AngularJs 中链接 Promise 的干净方法。我的目标是不使用 $q 重新包装 $http 承诺,而是利用 $http.xxx() 方法返回承诺并使用链接的事实。在下面的代码中,我试图满足以下用例。

注意:如果我删除了内部的 .catch() 块,我的 404 将被外部的 catch() 捕获。我尝试过使用 then(actionHandler, errorHandler) 方法以及尝试从 .catch() 返回一个字符串并尝试在 .catch() 中使用 this.reject()。

Give $scope.username is Bret 
When calling getPosts() and getting a 404 from /users 
Then scope.error has a message indicating that the user wasn't found

// 代码

angular.module('app', [])
    .controller('MainController', function ($scope, $log, $q, $http) {
        $scope.posts = [];
        $scope.message = "";

        function getUserByUserName(userName) {

            return getUsers()
                .then(function (response) {

                    var user;

                    for (var i = 0; i < response.data.length; i++) {
                        if (response.data[i].username === userName) {
                            user = response.data[i];
                            break;
                        }
                    }

                    return user;
                }).catch(function (error) {
                    throw "User could not be found.";
                });
        };

        function getUsers() {
            return $http.get('http://jsonplaceholder.typicode.com/users');
        }

        function getPostByUser(user){

            return getPosts()
                .then(function (posts) {

                    var postsByUser = [];

                    for (var i = 0; i < posts.length; i++) {
                        if (posts[i].userId === user.id) {
                            postsByUser.push(posts[i]);
                        }
                    }

                    return postsByUser;
                });
        }

        function getPosts() {
            return $http.get('http://jsonplaceholder.typicode.com/posts')
                .then(function (response) {
                    return response.data;
                });
        };

        function addPostsToScope(posts) {

            $log.debug('MainController.getPostByUserName reponse.length: ' + posts.length);

            $scope.posts.length = 0;

            $scope.posts.username = $scope.username;

            for (var i = 0; i < posts.length; i++) {
                $scope.posts.push(posts[i]);
            }
        };

        $scope.getPosts = function () {
            getUserByUserName($scope.username)
                .then(getPostByUser)
                .then(addPostsToScope)
                .catch(function (error) {
                        $scope.error = error;
                });
        };
    });

// 测试

describe('MainController', function () {

var endpointController;

var dummyPosts = [
    {
        "userId": 1,
        "id": 1,
        "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
        "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    },
    {
        "userId": 1,
        "id": 2,
        "title": "qui est esse",
        "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
    },
    {
        "userId": 2,
        "id": 11,
        "title": "et ea vero quia laudantium autem",
        "body": "delectus reiciendis molestiae occaecati non minima eveniet qui voluptatibus\naccusamus in eum beatae sit\nvel qui neque voluptates ut commodi qui incidunt\nut animi commodi"
    }];

var dummyUsers = [
    {
        "id": 1,
        "name": "Leanne Graham",
        "username": "Bret",
        "email": "Sincere@april.biz",
        "address": {
            "street": "Kulas Light",
            "suite": "Apt. 556",
            "city": "Gwenborough",
            "zipcode": "92998-3874",
            "geo": {
                "lat": "-37.3159",
                "lng": "81.1496"
            }
        },
        "phone": "1-770-736-8031 x56442",
        "website": "hildegard.org",
        "company": {
            "name": "Romaguera-Crona",
            "catchPhrase": "Multi-layered client-server neural-net",
            "bs": "harness real-time e-markets"
        }
    },
    {
        "id": 2,
        "name": "Ervin Howell",
        "username": "Antonette",
        "email": "Shanna@melissa.tv",
        "address": {
            "street": "Victor Plains",
            "suite": "Suite 879",
            "city": "Wisokyburgh",
            "zipcode": "90566-7771",
            "geo": {
                "lat": "-43.9509",
                "lng": "-34.4618"
            }
        },
        "phone": "010-692-6593 x09125",
        "website": "anastasia.net",
        "company": {
            "name": "Deckow-Crist",
            "catchPhrase": "Proactive didactic contingency",
            "bs": "synergize scalable supply-chains"
        }
    }];

beforeEach(module('app'));

it('Give $scope.username is Bret When calling getPosts() and getting a 404 from /users Then scope.error has a message indicating that the user wasnt found',
    inject(function ($rootScope, $controller, $httpBackend) {

        $httpBackend.whenGET('http://jsonplaceholder.typicode.com/users')
            .respond(404, null, null, "Not Found");
        $httpBackend.whenGET('http://jsonplaceholder.typicode.com/posts')
            .respond(dummyPosts);

        var scope = $rootScope.$new();

        scope.username = 'Bret';

        endpointController = $controller("MainController", { $scope: scope });

        scope.getPosts();

        $httpBackend.flush();

        expect(endpointController).toBeTruthy();
        expect(scope.error).toBeTruthy();
        expect(scope.error).toBe("User could not be found.");
    }));

});

编辑 我在这里添加了一个显示问题的 plunker:http://plnkr.co/edit/URMFfeM9IHPUGDbydZfa?p=preview

预期的控制台输出是

That user could not be found.
outer catch block reached!

但它正在写出来

That user could not be found.
getPosts
getPosts.Then()
getPostsByUser()

【问题讨论】:

  • 问题是什么?
  • 抱歉混淆,澄清问题是如何让内部捕获传播到外部捕获。

标签: javascript angularjs promise angular-promise


【解决方案1】:

在 catch 中使用return $q.reject(error)

return getUsers()
    .then(function (response) {
        var user;

        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].username === userName) {
                user = response.data[i];
                break;
            }
        }

        return user;
    }).catch(function (error) {
        return $q.reject(error);
    });

Plunkr 带有一个小演示,演示如何捕获异常并重新抛出它。

【讨论】:

  • 这清楚地展示了我正在尝试做的事情,但由于某种原因,我无法让它在我的代码中工作。我已经用我的代码路径的精简演示更新了你上面的 Plunkr,但它不起作用。它看起来与您的非常相似,但我似乎无法发现导致它破裂的差异。您有没有发现导致问题的原因?
猜你喜欢
  • 2014-06-13
  • 2017-06-03
  • 1970-01-01
  • 2021-11-06
  • 2014-10-27
  • 2018-04-05
  • 2019-05-10
  • 2018-01-31
  • 1970-01-01
相关资源
最近更新 更多