Promise 的基本使用
在ES6出来之后,有很多关于Promise的讲解、文章,也有很多经典的书籍讲解Promise
- 虽然等你学会Promise之后,会觉得Promise不过如此,但是在初次接触的时候都会觉得这个东西不好理解;
那么这里我从一个实际的例子来作为切入点: - 我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟);
- 如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去;
- 如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息
在ES6之前,使用回调函数取得一个异步函数返回结果,有以下弊端:
- 需要自己封装、设计回调函数名称;
- 如果用第三方库,则必须要看文档才能了解如何取得结果;
例子:
function request(url, callback, failCallback) {
setTimeout(() => {
// 请求接口模拟成功
const result = '成功'
if (result === '成功') {
callback(result)
} else {
// 失败
failCallback(result)
}
}, 3000)
}
// 传入两个回调函数
request('/api', function(result){}, function(result){})
更好的方案,Promise
,相当于规范了回调方式。规范成功时回调第一个函数 resolve
,失败时回调第二个函数 reject
。
- 不需要自己设计异步函数;
- 减少沟通成本,不看文档就能知道如何使用。
function request(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 请求接口模拟成功
const res = '成功'
if (res === '成功') {
resolve(res)
} else {
// 失败
reject(res)
}
}, 3000)
})
}
// 写法1
request('/api')
then((res) => {
console.log('成功回调')
}).catch((res) => {
console.log('失败的回调')
})
// 写法2,then中写入两个参数
request('/api')
then((res) => {
console.log('成功回调')
}, (res) => {
console.log('失败的回调')
})
Promise 的三种状态
- 待定
pending
状态:初始状态,没有被兑现,也没有被拒绝(当执行executor
中的代码时,处于该状态); - 已成功(已兑现)
fulfilled
或resolve
状态:操作成功完成; - 已拒绝
rejected
状态:操作失败;
状态一旦确定下来,那么就不可更改。
new Promise((resolve, reject) => {
// pending 状态
resolve()
}).then(res => {
// fulfilled 状态
}, err => {
// rejected 状态
})
Promise resolve 参数
/**
* resolve(参数)
* 1: 可传入普通的值或者对象
* 2: 或传入一个Promise
* 当传入一个Promise,不会立即执行.then或.catch,
* 而是看传入的Promise是执行resolve还是reject
* 3: 可传入一个对象,且对象实现有then方法(实现thenable),对象内的then方法会被执行。promise的.then不再实行
*/
const newPromise = new Promise((resolve, reject) => {
reject()
})
new Promise((resolve, reject) => {
resolve(newPromise)
}).then(res => {
console.log('成功')
}, res => {
// 会走到这里
console.log('失败')
})
Promise 对象方法 then方法 接受两个参数
then
方法是 Promise
对象上的一个方法:它其实是放在 Promise
的原型上的 Promise.prototype.then
。
接受两个参数:
fulfilled
的回调函数:当状态变成fulfilled
时会回调的函数;reject
的回调函数:当状态变成reject
是会回调的函数。
返回值
then方法本身是有返回值的,它的返回值是一个 Promise
,所以我们可以进行如下的链式调用:
- 但是then方法返回的
Promise
到底处于什么样的状态呢?
Promise
有三种状态 ,那么这个Promise
处于什么状态呢? - 当
then
方法中的回调函数本身在执行的时候,那么它处于pending
状态; - 当
then
方法中的回调函数返回一个结果时,那么它处于fulfilled
状态 ,并且会将结果作为resolve
的参数:- 返回一个普通的值;
- 返回一个
Promise
; - 返回一个
thenable
值;
- 当
then
方法抛出一个异常时,那么它处于reject
状态;
// 1. 同一个 Promise 可以被多次调用 .then
const promise = new Promise((resolve, reject) => {
resolve('yes')
})
promise.then((res) => {
// 会被执行
})
promise.then((res) => {
// 会再次被执行
})
promise.then((res) => {
// 会再再次被执行
})
// 2. then方法传入的回调函数:可以有返回值
// then方法本身也有返回值,它的返回值是Promise
// 1. 如果我们返回一个普通值,这个普通值会被作为一个新的Promise的resolve值
promise.then(res => {
return 'aaa'
}).then(res => {
// 打印 'aaa'
console.log(res)
})
// 2. 如果我们返回一个Premise
promise.then(res => {
return new Promise((resolve, reject) => {
resolve('no')
})
}).then(res => {
// 打印 'no'
console.log(res)
})
// 3. 如果我们返回一个实现了then函数的对象
promise.then(res => {
return {
then() {
return 'good'
}
}
}).then(res => {
// 打印 'good'
console.log(res)
})
Promise 对象方法 catch 方法
catch
方法也是 Promise
对象上的一个方法:它也是放在 Promise
的原型上的 Promise.prototype.catch
。
一个 promise
的 catch
方法是可以被名次调用的:
- 每次调用我们都可以传入对应的
reject
回调; - 当
Promise
的状态变成reject
的时候,这些回调函数都会被执行;
错误抛出方式1:
const promise = new Promise((resolve, reject) => {
reject('rejected status')
})
promise.then(undefined, err => {
// 打印 'rejected status'
console.log(err)
})
错误抛出方式2:
const promise = new Promise((resolve, reject) => {
throw new Error('rejected status')
})
promise.then(undefined, err => {
// 打印 err 的整个堆栈
console.log(err)
})
错误捕捉 catch
const promise = new Promise((resolve, reject) => {
throw new Error('rejected status')
})
// 写法1:then中写第二个回调
promise.then(undefined, err => {
// 打印 err 的整个堆栈
console.log(err)
})
// 写法2:优先捕捉先抛出错误的异常
promise.then(res => {
throw new Error('then error msg')
}).catch(err => {
// 打印 err 的整个堆栈
console.log(err)
})
// 写法3:写法不算 promise a+ 规范,node环境不支持此写法
promise.catch(err => {
// 打印 err 的整个堆栈
console.log(err)
})
Promise 对象方法 finally 方法 ES9(ES2018)
const promise = new Promise((resolve, reject) => {
resolve('resolve msg')
})
promise.then(res => {
console.log('res', res)
}).catch(err => {
console.log(err)
}).finally(() => {
// 完成后每次都会执行
console.log('finally code execute')
})
Promise 类方法 resolve reject
Promise.resolve
方法参数:
- 传入普通值,转换成一个
Promise
; - 传入
Promise
; - 传入
thenable
;
// 1. 传入普通值
Promise.resolve({name: 'tom'})
// 等于如下代码
new Promise(resolve => {
resolve({name: 'tom'})
})
// 2. 传入Promise
const promise = Promise.resolve(new Promise((resolve, reject) => {
resolve("11111")
}))
promise.then(res => {
// 打印 11111
console.log("res:", res)
})
// 3. 传入thanable,略
Promise.reject
方法参数:
const promise = Promise.reject('rejected msg')
// 相当于
// const promise2 = new Promsie((resolve, reject) => {
// reject ("rejected msg")
// })
// 注意:无论传入什么值都是一样,最终都会打印出reject括号内的内容
const promise = Promise.reject(new Promise(() => {}))
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
Promise 类方法 all allSettled(ES11) 方法
Promise.all()
当括号内所有的Promise
全部完成时获取结果,如果有一个失败,那整个Promise
就失败。
all
方法有一个缺陷:当有其中一个Promise
变成reiect
状态时,新Promise
就会立即变成对应的reject
状态。- 那么对于
resolved
的,以及依然处于pending
状态的Promise
,我们是获取不到对应的结果的;
- 那么对于
- 在ES11( ES2020)中,添加了新的API
Promise.allSettled
:- 该方法会在所有的
Promise
都有结果(settled
),无论是fulfilled
,还是reject
时,才会有最终的状态; - 并且这个
Promise
的结果一定是fulfilled
的:
- 该方法会在所有的
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 2000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 2000)
})
// 意外情况,当有promise rejected时,那么整个promise是rejected
// 有一个失败就执行 .catch
Promise.all([p1, p2, p3, 'aaa']).then((res) => {
// 打印 [111, 222, 333, 'aaa']
console.log(res)
})
const p4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(444)
}, 2000)
})
Promise.allsettled([p1, p4]).then(res => {
// 打印 {status: 'fulfilled', value: 111, status: 'rejected': 444}
console.log(res)
}).catch(err => {
console.log(err)
})
Promise 类方法 race any(ES12 ES2021) 方法
Promise.race()
数组中有一个 Promise
成功时,就成功。但是如果在成功之前,有一个失败,那就执行 reject
。
Promise.any()
有一个成功时才会取得结果,如果全部失败会执行 catch
。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 2000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
}, 3000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 4000)
})
const p4 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(333)
}, 1000)
})
Promise.race([p1, p2, p3]).then(res => {
// 打印 111
console.log(res)
})
Promise.any([p1, p2, p3, p4]).then(res => {
// 同样打印 111
console.log(res)
})
# 完结撒花