在有多个网络请求且下一个网络的请求结果依赖于上一个时,代码需要这样写:
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
当嵌套很深的时候,这个回调金字塔就失控了,使得开发人员非常痛苦,但有了promise后,可以这样写:其中每一个then函数的参数会依赖于上一个then的结果。
Q.fcall(promisedStep1)
.then(function(parms){
return key1;
})
.then(function(key1){
return key2;
})
.then(function(key2){
return key3;
})
.then(function (key3) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.done();
代码可读性变高了,也更易理解。promise是一种异步方式处理值得方法。promise是一个对象,代表一个函数最终可能的返回值或者抛出的异常。
以下是一个例子。重点理解注释部分。
angular.module('myApp', [])
.controller('DashboardController', [
'$scope', 'GithubService',
function($scope, GithubService) {
GithubService.getPullRequests()
//then中有三个参数,分别是成功回调、失败回调、状态变更回调,
//无论promise成功还是失败了,当结果可用之后,then都会立刻异步调用successFu或者errFn,并总会返回一个新的派生promise对象
.then(function(data) {
console.log("data from resolve", data);
$scope.pullRequests = data;
})
}])
.factory('GithubService', [
'$q', '$http',
function($q, $http) {
var getPullRequests = function() {
//defer()用于创建一个deferred对象
var deferred = $q.defer();
// Get list of open angular js pull requests from github
$http.get('http://www.runoob.com/try/angularjs/data/sites.php')
.success(function(data) {
//resolve中传入的变量或者函数返回结果,会当作第一个then方法的参数
console.log("data", data);
deferred.resolve(data.sites[0]);
})
.error(function(reason) {
deferred.reject(reason);
})
//defer.promise用于返回一个promise对象,来定义then方法(then方法是promise对象的方法)
return deferred.promise;
}
return {
getPullRequests: getPullRequests
};
}]);
通过打印log可以验证:resolve中传入的变量或者函数返回结果,会当作第一个then方法的参数
延迟调用是实现promise的方式,调用deferred.resolve()方法会填充promise(本质是最终调用success处理函数),而调用reject方法将会调用promise的错误处理函数。
HTML就可以在视图中调用了
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="http://cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js"></script>
</head>
<body>
<h1>Open Pull Requests for Angular JS</h1>
<ul ng-controller="DashboardController">
<li>
{{ pullRequests.name }} {{ pullRequests.country}}
</li>
</ul>
</body>
</html>