promise是JavaScript中处理异步事务的一种方式,这样的事务会在后续的某个时间点上完成。通常会在使用Ajax请求的时候使用到promise,浏览器在后台发起HTTP请求,并且在请求完成后使用promise通知相应的应用程序。以下程序示例,演示了一个极简单的AngularJS应用,并在其中调用Ajax请求。
<!DOCTYPE html>
<html ng-app="demo">
<head>
<meta charset="utf-8">
<title>Example</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body ng-controller="demoCtrl">
<div class="panel"></div>
<h1>To Do</h1>
<table class="table">
<tr>
<td>Action</td>
<td>Done</td>
</tr>
<tr ng-repeat="item in todos">
<td>{{item.action}}</td>
<td>{{item.done</td>
</tr>
</table>
<script src="angular.js"></script>
<script>
var app = angular.module('demo', []);
app.controller('demoCtrl', ['$scope', '$http', function ($scope, $http) {
var promise = $http.get('todo.json');
promise.success(function(data){
$scope.todos = data;
})
}])
</script>
</body>
</html>
为了演示promise是如何工作的,我还需要设置AngularJS中的模块、控制器、视图等组成部分。其中关键的代码如下:
var promise = $http.get('todo.json');
promise.success(function(data){
$scope.todos = data;
});
$http服务用来发起Ajax请求,它的get方法接受你想从服务端获得文件的URL作为参数。
Ajax请求的处理是异步的,在这个请求的过程,浏览器会继续执行其它的代码。$http.get方法会返回一个promise对象,通过这个对象可以获取Ajax请求的相关信息。如在这个例子中,我使用了success方法来注册一个回调函数,这个回调函数将在请求成功完成之后被调用。回调函数接收从服务端返回的数据,我将这些数据赋值给了$scope对象的todos属性,这样,也为ng-repeat指令提供了在表格中需要显示的内容。success方法是在promise对象中定义的三个方法中的其中一个,如下表所示:
promise对象中定义的方法
名称 | 描述 |
error(callback) | 指定一个回调函数,这个回调函数将在promise处理的任务未能成功完成时被调用 |
success(callback) | 指定一个回调函数,这个回调函数将在promise处理的任务成功完成时被调用 |
then(success, err) | 为promise分别指定一个执行成功或失败的回调函数 |
三个方法的参数都是函数,而这些函数将根据promise执行的结果决定是否被执行。可以将从服务端获得的数据传给success方法的回调函数中,而error方法的回调函数中可以得到错误的详细信息。
三个promise方法还可以返回其他的promise对象,这样就可以将异步的任务通过链式的写法写在一起,如下:
<!DOCTYPE html>
<html ng-app="demo">
<head>
<meta charset="utf-8">
<title>Example</title>
<link rel="stylesheet" href="boostrap3/css/bootstrap.min.css" />
</head>
<body ng-controller="demoCtrl">
<div class="panel">
<h1>To Do</h1>
<table class="table table-striped">
<tr>
<td>Action</td>
<td>Done</td>
</tr>
<tr ng-repeat="item in todos">
<td>{{item.action}}</td>
<td>{{item.done}}</td>
</tr>
</table>
</div>
<script src="js/angular/angular.min.js"></script>
<script>
var myApp = angular.module('demo', []);
myApp.controller('demoCtrl', ['$scope', '$http', function($scope, $http){
$http.get('data/todo.json').then(function(response){
$scope.todos = response.data;
}, function(){
$scope.todos = [{action: 'Error'}];
}).then(function(){
$scope.todos.push({action: 'Request Complete'})
})
}])
</script>
</body>
</html>
这里两次使用了then方法,第一次用以处理$http.get请求的响应,并且还注册了一个随后会被调用的函数。这样的代码可能会难以阅读,所以下面可以分步来了解它们。首先,调用get方法来创建一个Ajax请求:
<strong>$http.get('data/todo.json')</strong>.then(function(response){
$scope.todos = response.data;
}, function(){
$scope.todos = [{action: 'Error'}];
}).then(function(){
$scope.todos.push({action: 'Request Complete'})
});
接着,使用then方法,并且提供了在Ajax请求完成时会被调用的回调函数。当请求成功时会调用第一个函数,而失败时会执行第二个函数。
$http.get('data/todo.json').<strong>then(function(response){
$scope.todos = response.data;
}, function(){
$scope.todos = [{action: 'Error'}];
})</strong>.then(function(){
$scope.todos.push({action: 'Request Complete'})
});
promise确保了这两个函数会被执行,但是只有在Ajax请求成功完成或失败的时候才会执行。随后再次使用了then方法添加了另一个函数:
$http.get('data/todo.json').then(function(response){
$scope.todos = response.data;
}, function(){
$scope.todos = [{action: 'Error'}];
})<strong>.then(function(){
$scope.todos.push({action: 'Request Complete'})
})</strong>;
这次只传了一个函数给then方法,意味着我们不处理出错的情况。最后个函数不管前面的函数是否被调用都会想数据模型里面添加一个数据项。Ajax请求调用成功的效果如下图所示: