Promise是一个让开发者更合理、更规范地用于处理异步操作的对象,它有三种状态:初始化、操作成功、操作异常。使用实例方法:then( ) 和 catch( ) 来绑定处理程序;还提供了类方法:Promise.all( ) 和 Promise.race( )
Promise的设计初衷
- 日常开发中,经常需要用到ajax请求数据,拿到数据后,再进行一些处理,有时候你需要用ajax进行多次请求,而且,每次请求都依赖上一次请求返回的数据来作为参数,然后继续发出请求,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//------请求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,最后你也能顺利的完成了任务
传统写法的不足
- 如果存在多个请求操作层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也越来越差,不直观,调试起来也不方便。如果多人开发的时候没有足够的沟通协商,大家的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便
- 如果请求C的需要依赖A和B的结果,但是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间
既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。
传统的回调的方法 想要取出异步的a需要回调函数来操作
1 | function getData(){ |
1 | function getData1(){ |
- 回调拿到数据
1
2
3
4
5
6
7
8
9function getData(callback){
setTimeout(function(){//异步
var name='张三'
callback(name)
},1000)
}
getData(function(data){
console.log(data);
}) - 相当于
1
2
3
4
5
6
7
8
9
10
11//相当于
function getData(callback){
//在setTimeout执行完在执行
var callback = function(data){//实参
console.log(data);
}
setTimeout(function(){//异步
var name='张三'
callback(name)//形参
},1000)
}Promise的基本用法
1
2
3let pro = new Promise(function(resolve,reject){
//doSomething
}); - Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve和reject,两个函数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。
Promise的是三种状态
- Promise的是三种状态
- 1 pending:刚刚创建一个Promise实例的时候,表示初始
- 2 fulfilled:resolve方法调用的时候,表示操作成功;
- 3 rejected:reject方法调用的时候,表示操作失败;
1
2
3
4
5
6
7
8
9
10let pro = new Promise(function(resolve,reject){
//实例化后状态:pending
if('操作成功'){
resolve();
//resolve方法调用,状态为:fulfilled
}else{
reject();
//reject方法调用,状态为:rejected
}
});Promise的方法 then( )、catch( )
- then( )方法:用于绑定处理操作后的处理程序
- catch( )方法 用于操作异常的程序
1
2
3
4
5
6pro.then(function (res) {
//操作成功的处理程序
},function (error) {
//操作失败的处理程序
});1
2
3
4
5pro.then(function (res) {
//操作成功的处理程序
},function (error) {
//操作失败的处理程序
});代码练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//用new关键字创建一个Promise实例
let pro = new Promise(function(resolve,reject){
//假设condition的值为true
let condition = true;
if(condition){
//调用操作成功方法
var a = '蘑菇'
resolve(a);//传递参数
}else{
//调用操作异常方法
reject('操作异常');
}
});
//用then处理操作成功,catch处理操作异常
pro.then(function (res) {
console.log('准备买蘑菇',res)
}).catch(function (error) {
console.log(error)
});
//控制台输出:准备买蘑菇 蘑菇Promise实现多次请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40let 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实现传递参数给下一步操作的
可以在请求A的程序时使用return语句把需要的数据作为参数,传递给下一个请求
Promise.all( )方法
- Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//创建实例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.all( )方法的时候,会延迟到5秒才控制台会输出结果。
- 因为1000毫秒以后,实例pro2进入了成功fulfilled状态;此时,Promise.all( )还不会有所行动,因为实例pro1还没有进入成功fulfilled状态;等到了5000毫秒以后,实例pro1也进入了成功fulfilled状态,Promise.all( )才会进入then方法,然后在控制台输出
Promise.race( )方法 只返回第一条最先状态变化的数据
- 它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//创建实例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.race([pro1,pro2]).then(function(result){
console.log(result);
});
//打印结果:实例2操作成功Promise.race( )方法,只要有一个状态发生变化(不管是成功还是异常),它就会有返回,其他实例中再发生变化,它也不管了
Promise链式操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24var promiseFn1 = new Promise((resolve,reject)=>{
$.ajax({
url:url,,
type:'post',
success(res){
resolve(res)
},
error(err){
reject(err)
}
})
})
var promiseFn2 = new Promise((resolve,reject)=>{
$.ajax({
url:url,,
type:'post',
success(res){
resolve(res)
},
error(err){
reject(err)
}
})
}) - promiseFn1.then拿到promiseFn1请求成功的res
1
2
3
4
5
6
7promiseFn1.then((data)=>{
console.log('promiseFn1 success')
return promiseFn2;
}).then((data)=>{
//then是return promiseFn2;拿到的success的数据
console.log('promiseFn2 success')
})