在嵌套的承诺链中重新抛出异常
Rethrowing exceptions in nested promise chains
我正在尝试找到一种干净的方式来链接 AngularJs 中的承诺。我的目标是不使用 $q 重新包装 $http 承诺,而是利用 $http.xxx() 方法 return 承诺和使用链接这一事实。在下面的代码中,我试图满足以下用例。
注意:如果我删除内部 .catch() 块,我的 404 将被外部 catch() 捕获。我试过使用 then(actionHandler, errorHandler) 方法,也试过 returning 来自 .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()
在 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 带有一个演示捕获异常并重新抛出异常的小演示。
我正在尝试找到一种干净的方式来链接 AngularJs 中的承诺。我的目标是不使用 $q 重新包装 $http 承诺,而是利用 $http.xxx() 方法 return 承诺和使用链接这一事实。在下面的代码中,我试图满足以下用例。
注意:如果我删除内部 .catch() 块,我的 404 将被外部 catch() 捕获。我试过使用 then(actionHandler, errorHandler) 方法,也试过 returning 来自 .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()
在 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 带有一个演示捕获异常并重新抛出异常的小演示。