promise是什么?干什么用?
promise是异步编程的解决方案,原本的异步编程采用回调函数的方式获取返回的数据,在方法中传入一个回调函数当参数,当异步获取数据的时候调用这个回调函数并把数据传入,就可以获取数据。但是当一个回调函数嵌套另一个回调函数的时候,会出现回调地狱。
promise就是主要解决回调地狱的问题,让代码编写看起来像同步。
Promise是一个构造函数,通过new关键字实例化一个promise
1
2
3
4
|
const p = new Promise((resolve,reject)=>{
console.log(1111);
})
console.log(p);
|

可以看出new的时候会执行Promise中的函数,打印p实例PromiseState是实例pending状态
Promise对象的两个属性:
1.状态(PromiseState):pending表示进行中,fulfilled(已成功),rejest(已失败)
2.结果(PromiseResut):保存resolve或reject函数执行时传递的参数
1
2
3
|
const p = new Promise((resolve,reject)=>{
resolve("执行成功的回调")
})
|
当执行resolve函数时候,传递的参数会保存在PromiseResult中,并传递出去,在后面的then方法中调用第一个函数参数就是这个传递过来的值。实例的状态改为fulfilled(已成功)
当执行reject函数,传递的参数会保存在PromiseResult 中,并把错误作为参数传递出去。在后面的then方法的第二个函数中或catch方法里可以获取这个错误信息。实例的状态改为rejected
1
2
3
4
|
const p = new Promise((resolve,reject)=>{
reject("发生错误")
})
console.log(p);
|

当在调用then方法获取err后,PromiseResult为变为undefined
1
2
3
4
5
6
|
const p = new Promise((resolve,reject)=>{
reject("发生错误")
}).then(()=>{},(err)=>{
console.log(err);
})
console.log(p);
|

1.2 then方法
promise的then方法接受两个回调函数作为参数,第一个回调函数是Promise状态为fulfilled时候的会调用,第二个回调函数是Promise状态是reject时候会调用。在通常情况下第二个函数可以不写,用catch方法同样可以捕获错误!
1
2
3
4
5
6
7
8
9
10
|
const p = new Promise((resolve,reject)=>{
console.log(res);
//这里未定义使用变量会抛出错误,同样会让promise的状态变为rejected,catch就会捕获
})
p.then((data)=>{
console.log(data);
}).catch(err=>{
console.log(err);
})
console.log(p);
|

如果函数的返回值是一个promise就可以用then方法。
问题1. 如果Promise的状态没有发生改变,then()里的方法不会执行
示例:
1
2
3
4
5
6
7
8
|
const p = new Promise((resolve,reject)=>{
})
p.then((data)=>{
console.log("成功",data); //p的promiseState状态为pending 此时这个回调函数不会执行,
}).catch(err=>{
console.log("错误");
})
|
以上代码并不会输出任何语句。
示例2:
1
2
3
4
5
6
7
8
|
const p = new Promise((resolve,reject)=>{
console.log(x); //x没有定义,这里会抛出异常,抛出一个异常会把promiseState变为reject,会被catch捕获
})
p.then((data)=>{
console.log("成功",data); //p的promiseState状态为pending 此时这个回调函数不会执行,
}).catch(err=>{
console.log(err);
})
|

如果没有catch方法会在浏览器抛出错误

问题2 在then方法中,通过return将返回的Promise实例改为fulfilled状态
1
2
3
4
5
6
7
8
9
10
11
|
// 在then()方法中使用return 一个值或promise,会把状态改为fulfilled,返回的值会传递给下面的then方法
const p = new Promise((resolve,reject)=>{
resolve()
})
const t = p.then(value=>{
return 123 // 通过return 123 t的状态改为fulfilled,t.then()就会执行,打印123
}).then(value=>{
console.log(value);
}).catch(err=>{
console.log(err);
})
|
看下t的状态

1.4 Promise.prototype.catch()
catch什么时候会执行
- 当Promise的状态改为rejected的时候
1
2
3
4
|
const p = new Promise((resolve,reject)=>{
throw new Error('错误') //主动抛出个错误,p的状态改为rejected,相当于reject('错误')
}).then(data=>console.log(data))
.catch(err=>console.log(err))
|
- 当Promise中的代码执行发生错误的时候,执行catch
1
2
3
4
|
const p = new Promise((resolve,reject)=>{
console.log(x); // x没有被定义,抛出引用错误,将会被catch捕获打印出来
}).then(data=>console.log(data))
.catch(err=>console.log(err))
|
1.5 Promise.resolve()
此方法现有对象转为promise对象。
1
2
3
4
5
6
7
8
|
var p = Promise.resolve('hello') //将hello转为
//等价于
const p = new Promise(resolve=>{
resolve("hello")
})
p.then(data=>{
console.log(data);
})
|
参数’hello’是一个原始值,Promise.resolve()返回一个新的Promise对象,状态为resolved,p.then()方法将会执行。data就是hello。
1.6 Promise.all()
Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。
1
|
const p = Promise.all([p1,p2,p3])
|
新的Promise实例P的状态有p1,p2,p3决定,有两种情况
- p1,p2,p3的状态都是fulfilled,p的状态才会是fulfilled,p1,p2,p3的返回值组成一个数组,传递给P的.then()中的成功回调函数。
- p1,p2,p3中只要有个状态为rejected,p的状态就变成rejected,此时第一个rejected的实例的返回值会传递给p的catch中err回调函数。
示例1:p1,p2,p3的状态都是fulfilled
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
const p1 = new Promise((resolve,reject)=>{ // p1的状态是fulfilled
resolve('hello')
})
const p2= new Promise((resolve,reject)=>{ // p2 的状态是fulfilled
resolve("world")
})
const p3= new Promise((resolve,reject)=>{ // p3的状态是fulfilled
resolve("!!!")
})
Promise.all([p1,p2,p3]).then(data=>{ // p1,p2,p3都是fulfilled,才会执行then方法成功的回调
console.log(data.join(' '));
}).catch(err=>{
console.log(err);
})
|

示例2:有一个状态是rejected,这个实例的返回值会给catch捕获
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
const p1 = new Promise((resolve,reject)=>{
resolve('hello')
})
const p2= new Promise((resolve,reject)=>{ // p2 的状态是reject ,p将会执行catch的回调得到它的返回值
reject("发生错误")
})
const p3= new Promise((resolve,reject)=>{
resolve("!!!")
})
Promise.all([p1,p2,p3]).then(data=>{
console.log(data.join(' '));
}).catch(err=>{
console.log(err);
})
|

1.7 Promise.race()
Promise.race()同样是将多个Promise实例包装成一个新的Promise实例。
1
|
const p = Promise.race([p1,p2,p3])
|
上面代码中,只要p1,p2,p3中的一个有状态发生改变,p的状态就跟着改变。谁先改变状态,谁的值就会传递给p的回调函数。先到先得。race比赛的意思,字面意思就是谁先到就有优先。而不管是resolve还是reject。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
const p1 = new Promise((resolve,reject)=>{
return $.ajax({
method:'get',
url:'data1.json',
success:function(res){
resolve(res)
}
})
})
const p2 = new Promise((resolve,reject)=>{
setTimeout(() => {
reject(new Error('错误'))
},9); // 这里设置p2 实例9毫秒后改变状态为reject,如果ajax请求没有在9秒内执行resolve函数,p2实例
// 会先改变为reject状态,此时p会执行catch函数中的回调函数,打印 ‘错误’
})
const p = Promise.race([p1,p2])
.then(data=>{
console.log(data);
})
.catch(err=>{
console.log(err);
})
|

测试<10毫秒ajax不会返回请求,所以p2状态先改变,p2一改变状态,p就跟着改变,p2的返回值就传递给p的回调函数。打印出 ‘错误’
修改时间为≥10毫秒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
const p1 = new Promise((resolve,reject)=>{
return $.ajax({
method:'get',
url:'data1.json',
success:function(res){
resolve(res)
}
})
})
const p2 = new Promise((resolve,reject)=>{
setTimeout(() => {
reject(new Error('错误'))
},10); //ajax在10秒前就会执行resolve()所以会正常输出请求的数据
})
const p = Promise.race([p1,p2])
.then(data=>{
console.log(data);
})
.catch(err=>{
console.log(err);
})
|

改为10毫秒后,ajax请求能返回数据了,执行resove,所以会把返回值res传递给.then方法,打印出data。
用promise简单的封装一个类似于axios的方法
axios在客户端的实现就是基于原生的XMLHttpRequest()
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
|
// 封装请求JSON数据的方法
function getJsonData(url){
// 返回一个promise
return new Promise((resolve,reject)=>{
// 创建一个XMLHttpRequest对象
const http = new XMLHttpRequest()
// 设置请求方法和请求路径
http.open("GET",url)
//设置返回数据类型
http.responseType = 'json'
// 设置请求头
http.setRequestHeader("Accept","application/json")
http.send()
//监听状态的改变
http.onreadystatechange = function(){
if (this.readyState!==4){
return
}
// 状态为200说明请求成功
if (this.status===200){
resolve(this.response)
}else{
reject(new Error(this.statusText))
}
}
})
}
// 接下来就可以调用getData,因为getData返回值是一个promise,这个写法是否和axios有点类似
getJsonData('data1.json').then((data)=>{
console.log(data);
}).catch(err=>{
console.log(err);
})
|