这里从这篇文章开始《彻底理解Javascript 中的 Promise》
http://doc.okbase.net/libin-1/archive/253716.html
es6在线练习,可以用http://www.es6fiddle.net/
我的理解:
promise对象通常为一段端函数代码,而且通常是一段异步处理才有意义,比如含有settimeout或ajax等。
function prms1(){ var promise = new Promise(function(resolve, reject){ setTimeout(function(){ console.log('执行任务1'); //2 resolve('执行任务1成功'); //3 --> 导致4调用 }, 2000); }); return promise; } var prms1 = prms1(); console.log('before then'); prms1.then(function(data){ //1 console.log('第1个回调: ' + data); //4 })
代码中我标注了执行顺序,promise的then函数用来注册一个将要调用的回调,可以多个then链式写出来,但都不会执行,只是注册。
当在该promise里调用resolve时,设置状态为允许,才能调用执行then里函数。所以是按我标出的顺序执行的。
多加一个then看看效果:
function prms1(){ var promise = new Promise(function(resolve, reject){ setTimeout(function(){ console.log('执行任务1'); //2 resolve('执行任务1成功'); //3 --> 导致4调用 }, 2000); }); return promise; } var prms1 = prms1(); console.log('before then'); prms1.then(function(data){ //1 console.log('第1个回调: ' + data); //4 //return 'abc'; }).then(function(data){ console.log('第2个回调: ' + data); //5 });
执行后,控制台输出
before then 执行任务1 第1个回调: 执行任务1成功 第2个回调: undefined
可以看到,后续的then也都会执行,因为then的回调默认将返回当前的promise,保证链式调用像jquery一样,我的理解,如果return的是非promise类型,都被认为返回了当前的promise,且将返回的值带入下个then的回调入参中,可以查看return abc的效果
这样一来,好像这玩意儿也没啥大用处嘛。关键用途在下面,如果return的是一个Promise类型,就可以处理那个promise对象的函数了,并且由它来的resolve来控制它的then的执行,这样,就不会一长串then都被执行了,如下:
function prms1(){ var promise = new Promise(function(resolve, reject){ setTimeout(function(){ console.log('执行任务1'); //2 resolve('执行任务1成功'); //3 --> 导致4调用 }, 2000); }); return promise; } function prms2(){ var promise = new Promise(function(resolve, reject){ setTimeout(function(){ console.log('执行任务2'); //resolve('执行任务2成功'); },2000); }); return promise; } var prms1 = prms1(); console.log('before then'); prms1.then(function(data){ //1 console.log('第1个回调: ' + data); //4 return prms2(); }).then(function(data){ console.log('第2个回调: ' + data); });
运行后输出
before then 执行任务1 第1个回调: 执行任务1成功 执行任务2
可以看到,第二个then没有再执行了,因为它不受第一个promise控制了,它受prms2创建的新promise控制。将注释的resolve打开,看到
before then 执行任务1 第1个回调: 执行任务1成功 执行任务2 第2个回调: 执行任务2成功
因此,个人理解,在编写多回调嵌套的代码时,可以把每层嵌套放入一个promise对象中,用then来处理,并且注意每个then回调里return下一个promise
angular中,异步逻辑放在then中,具体参照此文章
https://my.oschina.net/ilivebox/blog/293771
var deferred = $q.defer(); var promise = deferred.promise; // resolve it after a second $timeout(function() { deferred.resolve('foo'); }, 1000); promise .then(function(one) { console.log('Promise one resolved with ', one); var anotherDeferred = $q.defer(); //在angular里使用promise处理多回调的常规写法 // resolve after another second // $timeout算是第一个异步操作的所有代码 $timeout(function() { //......这里省略异步的操作,在异步的最后resolve下一个promise anotherDeferred.resolve('bar'); //在angular里使用promise处理多回调的常规写法 }, 1000); return anotherDeferred.promise; //在angular里使用promise处理多回调的常规写法 }) .then(function(two) { console.log('Promise two resolved with ', two); });
这样就保证了then2里的回调在then1后才执行
在ajax中如此使用和封装
angular.module("MyService", []) .factory('githubService', ["$q", "$http", function($q, $http){ var getPullRequests = function(){ var deferred = $q.defer(); var promise = deferred.promise; var progress; $http.get("https://api.github.com/repos/angular/angular.js/pulls") .success(function(data){ var result = []; for(var i = 0; i < data.length; i++){ result.push(data[i].user); progress = (i+1)/data.length * 100; deferred.notify(progress); } deferred.resolve(result); }) .error(function(error){ deferred.reject(error); }); return promise; } return { getPullRequests: getPullRequests }; }]);
在项目中的使用心得
1. 所有基本promise和async里都不处理异常。在最上层的异步调用后才catch异常。否则底层catch后处理了 ,最上层就不会进入catch。
2. 接口的对于code的统一处理可以抽象出来,在最上层复用
3. promise里通过reject抛出异常,async里如果向主动抛出异常,用throw new Error。最终都在最上层调用中捕获到他们
4. reject('xxx') 和 throw new Error('xxx')稍有不同,在catch到e后,前者为e的值,后者为e.message的值