你的Promise
在JavaScript的世界里,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。
js中异步编程主要指的是setTimout/setInterval、DOM事件机制、ajax,通过传入回调函数实现控制反转。异步编程为js带来强大灵活性的同时,也带来了嵌套回调的问题。
1 2 3 4 5 6 
  | function callback() {     console.log('Done'); } console.log('before setTimeout()'); setTimeout(callback, 1000); // 1秒钟后调用callback函数 console.log('after setTimeout()'); 
  | 
 
串行执行若干异步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
  | function ajax(method,url,data){ var request=new XMLHttpRequest(); return new Promise(function(resolve,reject){ 		if(request.readyState===4){ 			if(request.status===200){ 				resolve(request.responseText); 			}else{ 			reject(request.status); 		} 			} 		request.open(method,url); 		request.send(data); }); } var log=document.getElementById("div"); var p=ajax('GET','/api/categories'); p.then(function(text){ 	log.innerText=text; }).catch(function(status){ 	log.innerText='ERROR:'+status; }); 
  | 
 
Promise还可以并行执行异步任务
- Promise.all()方法用于将多个Promise实例包装成一个新的Promise实例
var p=Promise.all([p1,p2,p3]);p1,p2,p3都是Promise对象的实例(Promise.all()参数只要是Iterator接口)分两种状态: 
- p1,p2,p3三者都是Fulfilled,p的状态才变成Fulfilled
 
- 只要p1,p2,p3中有一个被rejected则p就被rejected
 
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:
1 2 3 4 5 6 7 8 9 10 
  | var p1 = new Promise(function (resolve, reject) {     setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) {     setTimeout(resolve, 600, 'P2'); }); // 同时执行p1和p2,并在它们都完成后执行then: Promise.all([p1, p2]).then(function (results) {     console.log(results); // 获得一个Array: ['P1', 'P2'] }); 
  | 
有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
- Promise.race()方法,
var Promise.race([p1,p2,p3]);只要p1,p2,p3有一个实例率先改变状态,p的状态就会跟着改变,并且返回改变的那个实例的返回值就给p的回调函数。(而那些后面的返回值仍在执行,但被丢弃)1 2 3 4 5 6 7 8 9 
  | var p1 = new Promise(function (resolve, reject) {     setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) {     setTimeout(resolve, 600, 'P2'); }); Promise.race([p1, p2]).then(function (result) {     console.log(result); // 'P1' }); 
  | 
 
 
Promise的附加方法
- done()
Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。1 2 3 4 5 
  | asyncFunc()   .then(f1)   .catch(r1)   .then(f2)   .done(); 
  | 
 
 
它的实现代码非常简单
1 2 3 4 5 6 7 
  | Promise.prototype.done = function (onFulfilled, onRejected) {   this.then(onFulfilled, onRejected)     .catch(function (reason) {       // 抛出一个全局错误       setTimeout(() => { throw reason }, 0);     }); }; 
  | 
- finally()
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
下面是一个例子,服务器使用Promise处理请求,然后使用finally方法关掉服务器。1 2 3 4 5 
  | server.listen(0)   .then(function () {     // run test   })   .finally(server.stop); 
  | 
 
 
它的实现也很简单。
1 2 3 4 5 6 7 
  | Promise.prototype.finally = function (callback) {   let P = this.constructor;   return this.then(     value  => P.resolve(callback()).then(() => value),     reason => P.resolve(callback()).then(() => { throw reason })   ); }; 
  | 
参考链接:
http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000