//------请求A 开始--------- $.ajax({ success:function(res1){ //------请求B 开始---- $.ajax({ success:function(res2){ //----请求C 开始--- $.ajax({ success:function(res3){ } }); //---请求C 结束--- } }); //------请求B 结束----- } }); //------请求A 结束--------- 上面的案例,假设请求C须要依赖请求B返回的数据,因此,C只能放在B的success函数内;B须要依赖A请求获得的数据做为参数,因此,B只能放在A的success函数内;也就是:请求A包含着请求B,请求B又包含了请求C。 就这样,请求顺序为:请求A -> 请求B -> 请求C,最后你也能顺利的完成了任务。 传统写法的不足 可是这样写,会有一些缺点: 1. 若是存在多个请求操做层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也愈来愈差,不直观,调试起来也不方便。若是多人开发的时候没有足够的沟通协商,你们的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便。 2. 若是请求C的须要依赖A和B的结果,可是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须获得A请求完成后才能够执行,无疑是消耗了更多的等待时间。 既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,因此就有了Promise的出现了。 那么咱们就知道了:Promise对象能使咱们更合理、更规范地进行处理异步操做。 Promise的基本用法 接下来,咱们就看看它的基本用法: let pro = new Promise(function(resolve,reject){ //.... }); Promise对象是全局对象,你也能够理解为一个类,建立Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve和reject,两个函数均为方法。resolve方法用于处理异步操做成功后业务;reject方法用于操做异步操做失败后的业务。 Promise的是三种状态 Promise对象有三种状态: pending:刚刚建立一个Promise实例的时候,表示初始状态; fulfilled:resolve方法调用的时候,表示操做成功; rejected:reject方法调用的时候,表示操做失败; 状态只能从 初始化 -> 成功 或者 初始化 -> 失败,不能逆向转换,也不能在成功fulfilled 和失败rejected之间转换。 let pro = new Promise(function(resolve,reject){ //实例化后状态:pending if('操做成功'){ resolve(); //resolve方法调用,状态为:fulfilled }else{ reject(); //reject方法调用,状态为:rejected } }); 上面的注释,讲清楚了一个Promise实例的状态改变状况。 初始化实例后,对象的状态就变成了pending;当resolve方法被调用的时候,状态就变成了:成功fulfilled;当reject方法被调用的时候,状态就会有pending变成失败rejected。 then( )方法 了解了Promise的建立和状态,咱们来学习一个最重要的实例方法:then( )方法。 then( )方法:用于绑定处理操做后的处理程序。 pro.then(function (res) { //操做成功的处理程序 },function (error) { //操做失败的处理程序 }); 参数是两个函数,第一个用于处理操做成功后的业务,第二个用于处理操做异常后的业务。 catch( )方法 对于操做异常的程序,Promise专门提供了一个实例方法来处理:catch( )方法。 pro.catch(function (error) { //操做失败的处理程序 }); catch只接受一个参数,用于处理操做异常后的业务。 综合上面的两个方法,你们都建议将then方法用于处理操做成功,catch方法用于处理操做异常,也就是: pro.then(function (res) { //操做成功的处理程序 }).catch(function (error) { //操做失败的处理程序 }); 之因此可以使用链式调用,是由于then方法和catch方法调用后,都会返回promise对象。 讲了那么多,若是你以前一点都没接触过Promise的话,如今必定很懵逼,不要紧,下面咱们用一个案例来串联前面的知识点,演示一下,认真阅读注释: //用new关键字建立一个Promise实例 let pro = new Promise(function(resolve,reject){ //假设condition的值为true let condition = true; if(condition){ //调用操做成功方法 resolve('操做成功'); //状态:pending->fulfilled }else{ //调用操做异常方法 reject('操做异常'); //状态:pending->rejected } }); //用then处理操做成功,catch处理操做异常 pro.then(function (res) { //操做成功的处理程序 console.log(res) }).catch(function (error) { //操做失败的处理程序 console.log(error) }); //控制台输出:操做成功 上面案例的注释十分详细,串联起了上面介绍的全部知识点:建立实例,状态转换,then方法和catch方法的使用。 因为咱们设置了变量condition的值为true,因此执行后控制台输出的结果是:“操做成功”。 上面就是Promise用于处理操做异常的这个过程;可是,正如文章开头讲到的,若是多个操做之间层层依赖,咱们用Promise又是怎么处理的呢? 完整案例 咱们看看下面的案例,代码有点长,可是一点都不复杂: let pro = new Promise(function(resolve,reject){ if(true){ //调用操做成功方法 resolve('操做成功'); }else{ //调用操做异常方法 reject('操做异常'); } }); //用then处理操做成功,catch处理操做异常 pro.then(requestA) .then(requestB) .then(requestC) .catch(requestError); function requestA(){ console.log('请求A成功'); return '请求B,下一个就是你了'; } function requestB(res){ console.log('上一步的结果:'+res); console.log('请求B成功'); return '请求C,下一个就是你了'; } function requestC(res){ console.log('上一步的结果:'+res); console.log('请求C成功'); } function requestError(){ console.log('请求失败'); } //打印结果: //请求A成功 //上一步的结果:请求B,下一个就是你了 //请求B成功 //上一步的结果:请求C,下一个就是你了 //请求C成功 案例中,先是建立一个实例,还声明了4个函数,其中三个是分别表明着请求A,请求B,请求C;有了then方法,三个请求操做不再用层层嵌套了。咱们使用then方法,按照调用顺序,很直观地完成了三个操做的绑定,而且,若是请求B依赖于请求A的结果,那么,能够在请求A的程序用使用return语句把须要的数据做为参数,传递给下一个请求,案例中咱们就是使用return实现传递参数给下一步操做的。 更直观的图解 若是你仍是是懂非懂,不要紧,前端君拼了,上图: 图有点粗糙,可是能反应出上面程序的执行过程,帮助你们加深理解。 除了提供了实例方法之外,Promise还提供了一些类方法,也就是不用建立实例,也能够调用的方法。 下面,咱们来学习几个重要的。 Promise.all( )方法 Promise.all( )方法:接受一个数组做为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。 咱们来演示一下: //建立实例pro1 let pro1 = new Promise(function(resolve){ setTimeout(function () { resolve('实例1操做成功'); },5000); }); //建立实例pro2 let pro2 = new Promise(function(resolve){ setTimeout(function () { resolve('实例2操做成功'); },1000); }); Promise.all([pro1,pro2]).then(function(result){ console.log(result); }); //打印结果:["实例1操做成功", "实例2操做成功"] 上述案例,咱们建立了两个Promise实例:pro1和pro2,咱们注意两个setTimeout的第二个参数,分别是5000毫秒和1000毫秒,当咱们调用Promise.all( )方法的时候,会延迟到5秒才控制台会输出结果。 由于1000毫秒之后,实例pro2进入了成功fulfilled状态;此时,Promise.all( )还不会有所行动,由于实例pro1尚未进入成功fulfilled状态;等到了5000毫秒之后,实例pro1也进入了成功fulfilled状态,Promise.all( )才会进入then方法,而后在控制台输出:["实例1操做成功","实例2操做成功"]。 这个方法有什么用呢?通常这样的场景:咱们执行某个操做,这个操做须要获得须要多个接口请求回来的数据来支持,可是这些接口请求以前互不依赖,不须要层层嵌套。这种状况下就适合使用Promise.all( )方法,由于它会获得全部接口都请求成功了,才会进行操做。 Promise.race( )方法 另外一个相似的方法是Promise.race()方法:它的参数要求跟Promise.all( )方法同样,不一样的是,它参数中的promise实例,只要有一个状态发生变化(不论是成功fulfilled仍是异常rejected),它就会有返回,其余实例中再发生变化,它也无论了。 //初始化实例pro1 let pro1 = new Promise(function(resolve){ setTimeout(function () { resolve('实例1操做成功'); },4000); }); //初始化实例pro2 let pro2 = new Promise(function(resolve,reject){ setTimeout(function () { reject('实例2操做失败'); },2000); }); Promise.race([pro2,pro1]).then(function(result){ console.log(result); }).catch(function(error){ console.log(error); }); //打印结果:实例2操做失败 一样是两个实例,实例pro1不变,不一样的是实例pro2,此次咱们调用的是失败函数reject。 因为pro2实例中2000毫秒以后就执行reject方法,早于实例pro1的4000毫秒,因此最后输出的是:实例2操做失败。