Promise的介绍与使用——学习笔记
Promise
Promise
是JS中进行异步编程的新解决方案(以前使用回调函数来解决异步编程)
从语法上来说:Promise
是一个构造函数
从功能上来说:Promise
对象用来封装一个异步操作并且可以获取起成功或失败的结果值
一、Promise状态改变
Promise
共有三种状态pending
、resolved
(fulfilled
)、rejected
。
状态的改变只有两种可能:
-
pending
——>resolved
-
pending
——>rejected
如果Promise
的状态已经发生了改变,就不会在改变了。
二、Promise基本使用
通过resolved
设置状态为成功,通过rejected
设置状态为失败
通过then
方法对成功和失败的状态进行处理
例子1:点击按钮,1s后显示是否中奖(30%的中奖概率)
<body>
<div>
<h2>Promise 初体验</h2>
<hr />
<button id="btn">点击抽奖</button>
</div>
<script>
//生成随机数
function rand(m,n){
return Math.ceil(Math.random() * (n-m+1)) + m-1;
}
// 获取元素
const btn = document.querySelector('#btn')
// 绑定事件
btn.addEventListener('click', function() {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 获取从1-100的一个随机数
let n = rand(1,100)
// 判断
if (n <= 30) {
resolve(n) // 将 promise 对象的状态设置为【成功】
} else {
reject(n) // 将 promise 对象的状态设置为【失败】
}
}, 1000);
})
// console.log(p)
// 调用then方法
p.then((value) => {
alert(`success:${value}`)
}, (reason) => {
alert(`fail:${reason}`)
})
})
</script>
</body>
例子2:使用Promise
封装一个ajax
的get请求
function sendAJAX(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('GET', url)
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status)
}
}
}
})
}
sendAJAX('https://api.apiopen.top/getJoke').then(res => {
console.log(res)
}, reason => {
console.log(reason)
})
三、Promise中的API
3.1、Promise构造函数
-
executor
函数:执行器(resolve,reject) => {}
-
resolve
函数:内部定义成功时调用该函数 -
reject
函数:内部定义失败时调用该函数
3.2、then&catch
3.2.1、Promise.prototype.then方法
(onResolved, onRejected) => {}
-
onResolved
函数: 成功的回调函数 -
onRejected
函数:失败的回调函数
3.2.2、Promise.prototype.catch方法
(onRejected) => {}
onRejected
函数:失败的回调函数,相当于then()
方法的语法糖
let p = new Promise((resolve, reject) => {
console.log('11')
reject('error')
})
console.log('22')
// p.then(value => {}, reason => {})
p.catch(reason => {
console.log(reason)
})
注意:在Promise
中的代码是同步调用的,所以上面的代码会先输出11
再输出22
3.3、Promise.resolve方法
(value) => {}
快速返回一个Promise
对象
value
成功的数据或Promise
对象
-
传入的参数为非
Promise
类型的对象,则返回结果为成功 -
传入的参数为
Promise
对象,则参数结果决定了resolve
的结果
let p1 = Promise.resolve(1)
let p2 = Promise.resolve(new Promise((resolve, reject) => {
reject('error')
}))
console.log(p2)
p2.catch(reason => {
console.log(reason)
})
3.4、Promise.reject方法
(resone) => {}
resone
:失败的原因,方法会返回一个失败的对象,不论里面的数据是成功还是失败
let p = Promise.reject('3')
let p1 = Promise.reject(new Promise((resolve, reject) => {
resolve(3223)
}))
console.log(p)
console.log(p1)
3.5、Promise.all方法
(promises) => {}
返回一个新的Promise
,只有所有Promise
都成功才成功,只要有一个失败了就直接失败
promsies
:包含n
个Promsie
的数组
let p1 = new Promise((resolve, reject) => {
resolve('ok')
})
let p2 = Promise.resolve('success')
let p3 = Promise.reject('fail')
const result = Promise.all([p1, p2, p3])
console.log(result)
3.6、Promise.race方法
(promises) => {}
返回一个新的Promise
,第一个完成的Promise
的结果状态就是最终的结果状态
promises
:包含n
个Promsie
的数组
let p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
resolve('OK');
// }, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');
//调用
const result = Promise.race([p1, p2, p3]);
console.log(result);
四、Promise的关键问题
4.1、Promise的状态如何改变
-
resolve(value)
:如果当前是pending
就会变为resolved
-
reject(reason)
:如果当前是pending
就会变为rejected
-
抛出异常:如果当前是
pending
就会变为rejected
4.2、Promise指定多个成功或失败回调函数,都会调用吗
当Promise
改变为对应状态时都会调用
let p = new Promise((resolve, reject) => {
resolve('OK');
});
///指定回调 - 1
p.then(value => {
console.log(value);
});
//指定回调 - 2
p.then(value => {
alert(value);
});
4.3、改变Promise状态和指定回调函数谁先谁后
正常情况是先制定回调再改变状态,也可以先改变状态再指定回调
在执行器中直接调用resolve()/reject()
或者延迟更长的时间在调用then()
方法都可以使先改变状态再指定回调
如果先指定回调,当状态发生改变时,回调函数就会调用,得到数据
如果先改变状态,那当指定回调时,回调函数就会调用,得到数据
let p = new Promise((resolve, reject) => {
// setTimeout(() => {
resolve('OK');
// }, 1000);
});
p.then(value => {
console.log(value);
},reason=>{
})
4.4、Promise.prototype.then()返回的新Promise结果状态由什么决定
-
由
then()
指定的回调函数执行结果决定。-
如果抛出异常,新的
Promise
变为rejected
、reason
为抛出的异常 -
如果返回的是非
Promise
的任意值,新Promise
变为resolved
-
如果返回的是另一个新
Promise
,此Promise
的结果就会成为新Promise
的结果 -
如果没有返回值,则会返回一个成功状态的
Promise
值为undefined
-
let p = new Promise((resolve, reject) => {
// setTimeout(() => {
resolve('ok')
// }, 1000);
})
let result = p.then(value => {
console.log(value)
// 出错
// throw 'error'
// 不是promise
// return 521
// promise 对象
// return new Promise((resolve, reject) => {
// // resolve('success')
// reject('fail')
// })
}, reason => {
console.warn(reason);
})
console.log(result)
4.5、Promise如何串连多个操作任务
Promise
的then()
返回一个新的Promise
,可以看成then()
的链式调用。通过then
的链式调用串联多个同步或异步任务
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000);
})
p.then(value => {
return new Promise((resolve, reject) => {
resolve('success')
})
}).then(value => {
console.log(value)
}).then(value => {
console.log(value)
})
4.6、Promise异常穿透
当使用Promise
的then
链式调用时,可以在最后指定失败的回调,前面的操作出了任何异常,都会传到最后失败的回调中处理
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
// reject('Err');
}, 1000);
});
p.then(value => {
console.log(111);
}).then(value => {
throw '失败啦!';
// console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
4.7、中断Promise链
当使用Promise
的then
链式调用时,在中间中断后就不能再调用后面的回调,如果还想在后面调用回调函数,可以在回调函数中返回一个pendding
状态的Promise
对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(
// value => {
// console.log(111);
// 有且只有一个方式
// return new Promise(() => {});
// }
).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});