Promise简介
- Promise是JS中引入的一种新的提供异步编程的解决方案,旧的方案是使用回调函数。异步编程通常在以下情景中使用:
- Node.js下的fs模块的文件操作
- 数据库操作
- Ajax(网络请求)
- 定时器
- 使用Promise的优势
- 指定回调函数的方式更加灵活:旧的解决方案在启动异步任务前指定;而Promise可以在异步任务结束后指定一个或者多个回调。
- 支持链式调用,可以解决回调地狱的问题。
回调地狱:回调函数嵌套调用 缺点如下: 1. 代码可读性差 2. 不方便异常处理
- 使用Promise的简单示例:封装Ajax操作
<div>
<button id="btn">发送Ajax请求</button>
</div>
<script>
const btn = document.querySelector("#btn")
btn.addEventListener('click', function() {
// 创建Promise
sendAjax('http://api.apiopen.top/getJoke')
.then((value) => {
console.log(value)
}).catch((reason) => {
console.log(reason)
})
})
function sendAjax(url, method = 'get', async = true) {
return new Promise((resolve, reject) => {
//1.创建对象
const xhr = new XMLHttpRequest();
//2.初始化
xhr.responseType = 'json'
xhr.open(method, url, async)
//3.发送请求
xhr.send()
//4.处理响应结果
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// 判断响应状态码为2xx
if (xhr.status >= 200 && xhr.status < 300) {
// 请求响应成功则输出响应体
resolve(xhr.response)
} else {
// 失败则输出错误码
reject(xhr.status)
}
}
}
})
}
</script>
Promise理解
1.Promise中的状态
- Promise的状态就是一个Promise实例对象中的PromiseState属性。其值可能有三种:
- pending:未决定的。(初始状态)
- resolved/fullfilled:成功
- rejected:失败
- Promise的状态改变只有两种:由pending变为resolved、由pending变为rejected。一个Promise对象的状态只能改变一次,无论最终状态变为成功还是失败,都会有一个结果数据,成功的一般叫做value,失败的一般叫做reason
2.Promise对象的结果值
- Promise对象的结果值就是一个Promise实例对象的PromiseResult属性,保存着异步任务中对象成功或者失败的结果。resolve、reject函数可以对这个属性值进行修改。
const p = new Promise((resolve, reject) => {
let flag = true
if (flag) {
resolve(100)
}
})
// 其中PromiseState的值为fulfilled
// PromiseResult的值为100
console.log(p)
3.Promise中的相关方法
- util.promisify()方法:可以将回调函数风格的方法转化为Promise风格的函数。(nodejs中的方法)
- Promise构造函数:
Promise(executor)
。executor在Promise内部同步调用的。- executor函数:一个执行器,例如
(resolve, reject)=>{}
- resolve函数:在内部定义成功时调用的函数,例如(value) =>{}
- reject函数:在内部定义失败时调用的函数,例如(reason) =>{}
- executor函数:一个执行器,例如
- Promise.prototype.then方法:then方法内可以指定成功的回调函数和失败的回调函数
- Promise.prototype.catch方法:catch方法指定失败的回调函数
- Promise.resolve方法:参数为成功的数据或者Promise对象
// 如果传入的参数为非Promise的对象,则返回的结果为成功的Promise对象
// 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果。
- Promise.reject方法:参数为失败的原因,返回一个失败的Promise对象
- Promise.all方法:参数为promises,是一个包含n个promise的数组。返回一个新的Promise,只有所有的Promise都成功才成功,只要有一个失败就返回失败的Promise。
let p1 = new Promise((resolve, reject) => {
resolve('OK')
})
let p2 = Promise.resolve(520)
let p3 = Promise.resolve("I Love You")
const result = Promise.all([p1, p2, p3])
// 返回成功的Promise,结果值为每个Promise的结果值组成的数组
console.log(result)
- Prommise.race方法:参数为promises,是一个包含n个promise的数组。返回一个新的Promise,第一个完成的promise的结果状态就是最终的结果状态。
3.Promise的几个关键问题
- 改变Promise对象的状态
- 通过
resolve(value)
:如果当前是pending,就会变成resolved - 通过
reject(reason)
:如果当前是pending,就会变成rejected - 抛出异常:如果当前是pending,就会变成rejected
let p = new Promise((resolve, reject) => { throw '抛出异常' }) // Promise对象的状态为rejected console.log(p)
- 通过
- 为一个Promise对象指定多个成功或者失败的回调函数,是否都会调用:当Promise对象的状态由pending变为resolved或者由pending变为rejected时都会调用。
let p = new Promise(() => {
})
// p对象的状态还是pending,所以then函数不会执行
p.then(value => {
console.log(value)
})
- 改变Promise状态和指定回调函数的先后问题:都有可能,正常情况下先指定回调再改变状态,但是也可以先改变状态再指定回调。
- 如何先改变状态再指定回调:在执行器中直接调用resolve/reject函数或者延迟更长时间才调用then
- 如何先指定回调再改变状态:在异步回调中调用resolve或者reject
- 得到数据的时机:
- 如果先指定的回调,那当状态发生改变时,回调函数才会调用,得到数据
- 如果先改变的状态,那么当指定回调时回调函数就会调用得到数据。
- Promise.then方法返回的新的Promise对象的结果状态:由then方法指定的回调函数执行的结果决定。
- 如果抛出异常:新的Promise变为rejected,reason为抛出的异常
- 如果返回的是非Promise的任意值:新的Promise变为resolved,value为返回的值
- 如果返回的是另一个新的Promise,此Promise的结果就会成为新的Promise的结果。
- Promise串联多个同步或者异步的任务:通过Promise的then方法返回一个新的Promise对象,可以进行then函数的链式调用
- Promise异常穿透:当使用Promise的then的链式调用时,可以在最后指定失败的回调;前面任何操作出了异常,都会传到最后失败的回调中处理。
- 如何中断在Promise中的then方法的链式调用:在then方法的回调函数中返回一个pending状态的Promise对象