一、介绍
Promise是用来处理异步操作,使得异步代码可以和同步代码一样
1.用法
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve('成功的结果'); // 操作成功,调用resolve函数
}, 1000);
});
promise.then(result => {
console.log(result); // '成功的结果'
}).catch(error => {
console.log(error); // 不会执行,因为Promise已经被解析
});
2.特点
- promise有三种状态,分别是pending(进行中)、fulfilled(已成功)、rejected(已失败),
- 状态一旦发生改变,就不能再变 (即 pending -> fulfilled 、 pending -> rejected)
- 接受一个函数作为参数,该函数的参数为 resolve 和 reject
- resolve 作用:将Promise对象的状态从 pending => fulfilled
- reject 作用:将Promise对象的状态从pending => reject
3.方法介绍
- then() : 实例状态发生改变时的回调函数
- catch() : 用于指定发生错误时的回调函数
- finally() : 用于指定不管Promise对象最后状态如何,都会执行的操作
- all() : 接收一个Promise数组,每个请求都成功才会返回成功结果数组,否则会报错
- race() : 接收一个Promise数组,哪个最快返回,就返回哪个结果
- allSettled() : 接收一个Promise数组,无论成功与否,返回集合数组
- any():接收一个Promise数组,如果有一个成功,则返回成功,当所有都失败,则会报错
二、手写Promise基本功能
step1:
目的:初始化MyPromise
代码解析:
- 初始化参数
- promise有三种状态,定义状态变量 promiseStatus
- 最后返回的值,定义返回值变量 promiseResult
- promise有 resolve、reject 方法,定义 resolve、reject 方法
- 初始化this绑定
- resolve、reject绑定在实例上,谁调用指向谁
- 立即执行函数
代码编写:
class MyPromise{
constructor(executor){
this.initValue() // 1.初始化参数
this.initBind() // 2. 初始化this绑定
executor(this.resolve,this.reject) // 3.立即执行函数
}
initValue(){
this.promiseStatus = 'pending' // 状态
this.promiseResult = null // 返回的值
}
initBind(){
this.resolve = this.resolve.bind(this) // 绑定在实例上
this.reject = this.reject.bind(this)
}
// 定义 resolve、reject 方法
resolve(res){}
reject(err){}
}
测试一下:
new MyPromise((resolve, reject) => {
console.log('hello Promise') // hello Promise
})
step2:
目的:resolve和reject回调,三种状态转换
代码解析:
- promise的状态一旦发生改变,就不能再变,所以当状态为 pending 才会执行
- 改变promise的状态
- resolve 方法,把 promise 的状态从 pending -> fulfilled
- reject 方法,把 promise 的状态从 pending -> rejected
- 改变返回的值
- resolve 方法,promiseResult = res
- reject 方法,promiseResult = err
代码编写:
class MyPromise{
constructor(executor){
this.initValue()
this.initBind()
executor(this.resolve,this.reject)
}
initValue(){
this.promiseStatus = 'pending'
this.promiseResult = null
}
initBind(){
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(res){
if(this.promiseStatus === 'pending'){ // 1.状态一旦发生改变,就不能再变
this.promiseStatus = 'fulfilled' // 2. pending -> fulfilled
this.promiseResult = res // 3.改变返回的值
}
}
reject(err){
if (this.promiseStatus === 'pending') { // 1.状态一旦发生改变,就不能再变
this.promiseStatus = 'rejected' // 2. pending -> rejected
this.promiseResult = err // 3.改变返回的值
}
}
}
测试一下:
new MyPromise((resolve, reject) => {
resolve('1.成功') // {promiseStatus:"fulfilled",promiseResult:"1.成功"}
})
new MyPromise((resolve, reject) => {
reject('2.失败') // {promiseStatus:"rejected",promiseResult:"2.失败"}
})
new MyPromise((resolve, reject) => {
resolve('3.成功') // {promiseStatus:"fulfilled",promiseResult:"3.成功"}
reject('3.失败') // 不会执行
})
step3:
目的:实现then方法,实例状态发生改变时的回调函数
代码解析:
- then接受2个参数
- resolved()后 的回调函数 onFulfilled
- rejected()后 的回调函数 onRejected
- 当调用resolved() , 状态发生改变为 fulfilled 时,执行回调函数 onFulfilled
- 当调用rejected() , 状态发生改变为 onRejected 时,执行回调函数 onRejected
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res){...}
reject(err) {...}
then(onFulfilled,onRejected){
if(this.promiseStatus === 'fulfilled'){
onFulfilled(this.promiseResult)
}else if(this.promiseStatus === 'rejected'){
onRejected(this.promiseResult)
}
}
}
测试一下:
new MyPromise((resolve, reject) => {
resolve('成功')
}).then((res) => {
console.log('res:',res) // res: 成功
},(err) => {
console.log('err:',err)
})
new MyPromise((resolve, reject) => {
reject('失败')
}).then((res) => {
console.log('res:',res)
},(err) => {
console.log('err:',err) // err: 失败
})
step4:
目的:实现异步调用,让异步代码和同步一样
代码解析:
- resolve在setTimeout内执行,还没到resolve或reject方法,then中还是'pending'状态
- 采用先存后用,当调用then时,把成功 onFulfilled() 和失败 onRejected()存起来
- 定义成功回调数组onFulfilledCallback,保存成功 onFulfilled() 的集合
- 定义失败回调数组onRejectedCallback,保存失败 onRejected() 的集合
- 当走到resolve 或者 reject 再循环执行存起来的 回调函数
- 定义成数组,是因为后续我们需要 then 的链式调用,有多个onFulfilled() 和 onRejected()
- 所以到resolve和reject时,需要循环执行回调数组。
- this.onFulfilledCallback.shift(),提取第一个出来,相当于一个 onFulfilled()
- this.onFulfilledCallback.shift()(this.promiseResult),就相当于 onFulfilled(this.promiseResult)
代码编写:
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
executor(this.resolve, this.reject)
}
initValue() {
this.promiseStatus = 'pending'
this.promiseResult = null
this.onFulfilledCallback = [] // 2.成功回调数组
this.onRejectedCallback = [] // 2.失败回调数组
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(res) {
if (this.promiseStatus === 'pending') {
this.promiseStatus = 'fulfilled'
this.promiseResult = res
while(this.onFulfilledCallback.length){ // 3.循环执行
this.onFulfilledCallback.shift()(this.promiseResult)
}
}
}
reject(err) {
if (this.promiseStatus === 'pending') {
this.promiseStatus = 'rejected'
this.promiseResult = err
while(this.onRejectedCallback.length){// 3.循环执行
this.onRejectedCallback.shift()(this.promiseResult)
}
}
}
then(onFulfilled,onRejected){
if(this.promiseStatus === 'fulfilled'){
onFulfilled(this.promiseResult)
}else if(this.promiseStatus === 'rejected'){
onRejected(this.promiseResult)
}else if(this.promiseStatus === 'pending'){ // 1.settimeout时,这里状态仍为 pengding
this.onFulfilledCallback.push(onFulfilled.bind(this)) // 2.保存成功 onFulfilled() 的集合
this.onRejectedCallback.push(onRejected.bind(this))// 2.保存失败 onRejected() 的集合
}
}
}
测试一下:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
},500)
}).then((res) => {
console.log('res:',res) // 500ms后 res: 成功
})
step5:
目的:实现then的链式调用,后一个then可以获取到前一个return的值
代码解析:
- 要想链式调用,返回的肯定是一个promise对象
- 如果值为promise,就看promise是成功还是失败,返回对应的值。只有.then才知道它是成功还是失败
- 如果值为非promise,直接成功resolve(x)
- 执行Promise A+标准,返回值不能为Promise本身,死循环。(ps:想不到什么情况会返回本身)
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {
let thenPromise = new MyPromise((resolve, reject) => { // 1.返回时promise对象
const resultPromise = (cb) => { // 提取一个公共方法
const x = cb(this.promiseResult) // 获取返回值,cb为传入的函数
if(x === MyPromise){
throw new Error('死循环')// 4.A+ 规范
}
if(x instanceof MyPromise){ // 2.值为promise
x.then(resolve,reject) // 2.只有.then才知道它是成功还是失败
}else{ // 值为非promise
resolve(x) // 3.直接成功返回
}
}
if (this.promiseStatus === 'fulfilled') {
resultPromise(onFulfilled) // 原本 onFulfilled(this.promiseResult)
} else if (this.promiseStatus === 'rejected') {
resultPromise(onRejected) // 原本 onRejected(this.promiseResult)
} else if (this.promiseStatus === 'pending') {
this.onFulfilledCallback.push(resultPromise.bind(this, onFulfilled))
this.onRejectedCallback.push(resultPromise.bind(this,onRejected))
// 原本 this.onFulfilledCallback.push(onFulfilled.bind(this))
// 原本 this.onRejectedCallback.push(onRejected.bind(this))
}
})
return thenPromise
}
}
测试一下:
new MyPromise((resolve, reject) => {
resolve(100)
}).then(res => {
console.log(res, '第一个then') // 100
return res * 2
}).then(res => {
console.log(res, '第二个then') // 200
return new MyPromise((resolve, reject) => {
resolve(res + 100)
})
}).then(res => {
console.log(res, '第三个then') // 300
})
step6:
目的:执行顺序
代码解析:
- Promise.then是微任务,外层执行应该比then要更快
- 按这个道理,只需要在then返回得时候执行setTimeout 同为微任务
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {
let thenPromise = new MyPromise((resolve, reject) => {
const resultPromise = (cb) => {
setTimeout(() => { // 添加setTimeout,形成微任务
const x = cb(this.promiseResult)
if (x === MyPromise) {
throw new Error('死循环')
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
}
if (this.promiseStatus === 'fulfilled') {
resultPromise(onFulfilled)
} else if (this.promiseStatus === 'rejected') {
resultPromise(onRejected)
} else if (this.promiseStatus === 'pending') {
this.onFulfilledCallback.push(resultPromise.bind(this, onFulfilled))
this.onRejectedCallback.push(resultPromise.bind(this, onRejected))
}
})
return thenPromise
}
}
测试一下:
new MyPromise((resolve, reject) => {
resolve(2)
}).then(res => {
console.log(res, 'then微任务后执行:2')
})
console.log('外层先执行:1')
// 外层先执行:1
// 2 then微任务后执行:2
step7:
目的:实现值穿透,多个then,最后一个then获取值
代码解析:
- 如果有回调函数,并且回调函数为function,即为promise,若不是,则直接传递
- 若不是,onFulfilled = (val) => val
- 若不是,onRejected = (err) => { throw err} // 报错
- 立即执行函数
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {
// 做穿透兼容
onFulfilled = typeof onFulfilled === 'function'?onFulfilled : (val) => val
onRejected = typeof onRejected === 'function'?onRejected : (err) => { throw err}
let thenPromise = new MyPromise((resolve, reject) => {
const resultPromise = (cb) => {
setTimeout(() => {
const x = cb(this.promiseResult)
if (x === MyPromise) {
throw new Error('死循环')
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
}
if (this.promiseStatus === 'fulfilled') {
resultPromise(onFulfilled)
} else if (this.promiseStatus === 'rejected') {
resultPromise(onRejected)
} else if (this.promiseStatus === 'pending') {
this.onFulfilledCallback.push(resultPromise.bind(this, onFulfilled))
this.onRejectedCallback.push(resultPromise.bind(this, onRejected))
}
})
return thenPromise
}
}
测试一下:
new MyPromise((resolve, reject) => {
resolve(2)
}).then().then().then().then().then().then().then((res) => {
console.log('res:',res) // res: 2
})
step8:
目的:异常捕获处理,按照A+标准做好异常捕获处理
代码解析:
- 异常捕获处理, 会导致promise往reject()走,实现异常捕获
代码编写:
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
// 异常捕获
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (val) => val
onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err }
let thenPromise = new MyPromise((resolve, reject) => {
const resultPromise = (cb) => {
setTimeout(() => {
try { // 异常捕获
const x = cb(this.promiseResult)
if (x === MyPromise) {
throw new Error('死循环') // 抛出给外层catch接收
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (e) {
this.reject(e)
throw new Error(e) // 抛出给下一个then接收
}
})
}
...
})
return thenPromise
}
}
到此为止,promise就完成了
三、手写Promise其他功能
all()
特点
- 接受一个Promise数组,数组中如有非Promise项,那么此项当成功
- 如果所有Promise都成功,就返回成功的数组
- 如果有一个Promise失败,就返回失败的结果
代码解析:
- 需要定义一个成功结果的数组 result,和用来计数的变量 count
- result用来存储对应的值,最后做成功的返回
- count每遍历一次count++,遍历完成,count === promises长度,即全部成功,返回数组
- 当遍历这个 Promise数组
- 如果是Prmise,就交给.then处理,只有.then才知道成功或失败
- 如果非Promise,那么此项当成功
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {...}
// all
static all(promises) {
let result = [] // 结果数组
let count = 0 // 计数
return new MyPromise((resolve, reject) => {
const addData = (index, value) => { // 提取公共方法,成功才会走的函数
result[index] = value // 存储结果
count++ // 遍历次数+1
if (count === promises.length) resolve(result) // 代表全成功,返回成功数组
}
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) { // 是否为Promise
promise.then((res) => { // 是,交给then处理
addData(index, res) // 成功,走成功存储
}, err => reject(err)) // 失败,直接结束,返回失败结果
} else {
addData(index, promise) // 非promise,则这项成功
}
})
})
}
}
测试一下
--- 成功示例
const p1 = 1
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},500)
})
const p3 = new MyPromise((resolve, reject) => {
resolve(3)
})
MyPromise.all([p1,p2,p3]).then(val => {
console.log(val) // [1,2,3]
})
--- 失败示例
const p4 = new MyPromise((resolve, reject) => {
reject(4)
})
MyPromise.all([p1,p2,p3,p4]).then(val => {
console.log(val) // 报错,Error: 4
})
rate()
特点
- 接受一个Promise数组,数组中如有非Promise项,那么此项当成功
- 哪个最快返回,就返回哪个结果
代码解析:
- 遍历这个 Promise数组
- 如果是Prmise,就交给.then处理,只有.then才知道成功或失败
- 如果非Promise,那么此项当成功
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {...}
// rate
static rate(promises) {
return new MyPromise((resolve,reject) => {
promises.forEach((promise,index) => {
if(promise instanceof MyPromise){
promise.then((res) => { // 是Prmise,交给then
resolve(res)
},(err) => reject(err))
}else{
resolve(promise) // 非Prmise,执行成功回调
}
})
})
}
}
测试一下
const p1 = 1
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(2)
},500)
})
const p3 = new MyPromise((resolve, reject) => {
resolve(3)
})
MyPromise.rate([p2,p3,p1]).then(val => {
console.log(val) // 1
})
MyPromise.rate([p2,p3]).then(val => {
console.log(val) // 3
})
allSettled()
特点
- 接受一个Promise数组,数组中如有非Promise项,那么此项当成功
- 把每个Promise的结果,无论成功失败,集合成数组后返回
代码解析:
- 结合all(),需要结果集合result和计数count
- 由于无论成功失败都需要存储,所以添加一个status进到集合里
- 无论成功失败,都不走rejected,当都成功,返回一个完整数组
- 其实就只是多了一个状态(成功 | 失败)
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {...}
// allSelect
static allSelect(promises){
return new MyPromise((resolve,reject) => {
const result = [] // 结果集合
let count = 0 // 计数
const addData = (status,value,index) => {
result[index] = {status,value} // 这里需要status,记录状态
count++// 计数
if(count === promises.length) resolve(result) // 遍历完成,返回结果
}
promises.forEach((promise,index) =>{
if(promise instanceof MyPromise){
promise.then((res) => {
addData('fulfilled',res,index) // 成功,记录成功状态
},err => {
addData('rejected',err,index)// 失败,当成功的去走,记录失败状态
})
}else{
addData('fulfilled',promise,index) // 成功,记录成功状态
}
})
})
}
}
测试一下
const p1 = 1
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
},500)
})
const p3 = new MyPromise((resolve, reject) => {
resolve(3)
})
MyPromise.allSelect([p1,p2,p3]).then(val => {
console.log(val)
/**[
* {status:'fulfilled',value:1}
* {status:'rejected',value:2}
* {status:'fulfilled',value:3}
* ]
*/
})
any()
特点
- 接受一个Promise数组,数组中如有非Promise项,那么此项当成功
- 和all()相反,如果有⼀个Promise成功,则返回这个成功结果
- 如果所有Promise都失败,则报错;
代码解析:
- 定义一个计数count变量,当count === promises长度,说明全失败,报错
- 遍历这个 Promise数组
- 如果是Prmise,就交给.then处理,只有.then才知道成功或失败
- 如果非Promise,那么此项当成功,直接不用处理
代码编写:
class MyPromise {
constructor(executor) {...}
initValue() {...}
initBind() {...}
resolve(res) {...}
reject(err) {...}
then(onFulfilled, onRejected) {...}
// any
static any(promises){
return new Promise((resolve,reject) => {
let count = 0 // 计数
promises.forEach((promise) => {
promise.then((res) => {
resolve(res) // 有一个成功,直接返回
},err => {
count++
if(count === promises.length){
reject('报错') // 全错,直接报错
}
})
})
})
}
}
测试一下
--- 有一个成功案例
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
},500)
})
const p3 = new MyPromise((resolve, reject) => {
resolve(3)
})
MyPromise.any([p2,p3]).then(val => {
console.log(val) // 3
})
--- 全都失败,报错案例
const p4 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
},500)
})
const p5 = new MyPromise((resolve, reject) => {
reject(1)
})
MyPromise.any([p4,p5]).then(val => {
console.log(val) // 报错
})
四、总结
动动小手,一起来编写吧~
完整代码
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
// 异常捕获
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initValue() {
this.promiseStatus = 'pending'
this.promiseResult = null
this.onFulfilledCallback = []
this.onRejectedCallback = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(res) {
if (this.promiseStatus === 'pending') {
this.promiseStatus = 'fulfilled'
this.promiseResult = res
while (this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()(this.promiseResult)
}
}
}
reject(err) {
if (this.promiseStatus === 'pending') {
this.promiseStatus = 'rejected'
this.promiseResult = err
while (this.onRejectedCallback.length) {
this.onRejectedCallback.shift()(this.promiseResult)
}
}
}
then(onFulfilled, onRejected) {
// 做穿透兼容
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (val) => val
onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err }
let thenPromise = new MyPromise((resolve, reject) => {
const resultPromise = (cb) => {
setTimeout(() => {
try {
const x = cb(this.promiseResult)
if (x === MyPromise) {
throw new Error('死循环') // 抛出给外层catch接收
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (e) {
this.reject(e)
throw new Error(e) // 抛出给下一个then接收
}
})
}
if (this.promiseStatus === 'fulfilled') {
resultPromise(onFulfilled)
} else if (this.promiseStatus === 'rejected') {
resultPromise(onRejected)
} else if (this.promiseStatus === 'pending') {
this.onFulfilledCallback.push(resultPromise.bind(this, onFulfilled))
this.onRejectedCallback.push(resultPromise.bind(this, onRejected))
}
})
return thenPromise
}
// all
static all(promises) {
let result = [] // 结果数组
let count = 0 // 计数
return new MyPromise((resolve, reject) => {
const addData = (index, value) => {
result[index] = value
count++
if (count === promises.length) resolve(result)
}
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then((res) => {
addData(index, res)
}, err => reject(err))
} else {
addData(index, promise)
}
})
})
}
// rate
static rate(promises) {
return new MyPromise((resolve,reject) => {
promises.forEach((promise,index) => {
if(promise instanceof MyPromise){
promise.then((res) => {
resolve(res)
},(err) => reject(err))
}else{
resolve(promise)
}
})
})
}
// allSelect
static allSelect(promises){
return new MyPromise((resolve,reject) => {
const result = []
let count = 0
const addData = (status,value,index) => {
result[index] = {status,value}
count++
if(count === promises.length) resolve(result)
}
promises.forEach((promise,index) =>{
if(promise instanceof MyPromise){
promise.then((res) => {
addData('fulfilled',res,index)
},err => {
addData('rejected',err,index)
})
}else{
addData('fulfilled',promise,index)
}
})
})
}
// any
static any(promises){
return new Promise((resolve,reject) => {
let count = 0
promises.forEach((promise) => {
promise.then((res) => {
resolve(res)
},err => {
count++
if(count === promises.length){
reject('报错')
}
})
})
})
}
}