写在最前,本文转自掘金
resolve和reject
这里有四个知识点
- 执行了
resolve
,Promise状态会变成fulfilled
- 执行了
reject
,Promise状态会变成rejected
- Promise只以第一次为准,状态改变就永久改变
- Promise中有
throw
的话,就相当于执行了reject
那么咱们就把这四个知识点一步步实现吧
1. 实现resolve与reject
注意,Promise的初始状态是pending
这里很重要的一步是resolve和reject的绑定this
,为什么要绑定this
呢,这是为了this
永远指向当前MyPromise实例,防止随着函数执行环境的改变而改变
class MyPromise{
constructor(executor){
// 初始化值
this.initValue()
// 初始化this指向
this.initBind()
// 执行传进来的函数
executor(this.resolve, this.reject)
}
initBind(){
// 在不同的作用域下调用处理函数,会让处理函数中的this失去方向
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initValue(){
this.PromiseResult = null // 终值
this.PromiseState = 'pending' // 状态
}
resolve(value){
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
}
reject(reason){
// 与resolve同理
this.PromiseState = 'rejected'
this.PromiseResult = reason
}
}
咱们来测试一下吧
const test1 = new MyPromise((resolve, reject) => {
resolve('成功')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }
const test2 = new MyPromise((resolve, reject) => {
reject('失败')
})
console.log(test2) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }
2. 状态不可变
上面代码还未做到状态永久不变,其实只需要判断PromiseState
是否改变就可以了
resolve(value) {
// state是不可变的
+ if (this.PromiseState !== 'pending') return
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
}
reject(reason) {
// state是不可变的
+ if (this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState = 'rejected'
// 终值为传进来的reason
this.PromiseResult = reason
}
3. throw
Promise中有throw
的话,相当于执行了reject。这就要使用try catch
了
+ try {
// 执行传进来的函数
executor(this.resolve, this.reject)
+ } catch (e) {
// 捕捉到错误直接执行reject
+ this.reject(e)
+ }
then
这有四个知识点
- then接收两个回调,一个是成功回调,一个是失败回调
- 当Promise状态为
fulfilled
执行成功回调,为rejected
执行失败回调 - 如
resolve
或reject
在定时器里,则定时器结束后再执行then - then支持链式调用,下次then执行受上一次then返回值的影响
1. 实现then
then(onFulfilled, onRejected){
// 接收两个回调,参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected: reason => { throw reason }
if(this.PromiseState === 'fulfilled'){
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
} else if(this.PromiseState === 'rejected'){
onRejected(this.PromiseResult)
}
}
2. 定时器情况
上面我们已经实现了then
的基本功能,那如果是定时器情况呢?
如何才能保证1秒后才执行then里的回调函数呢?
我们不能保证1秒后才执行then函数,但是我们可以保证1秒后再执行then里的回调
watermark1.jpg
我们只需要在执行了resolve或reject
函数后再调用之前存起来的回调函数,我们用数组来保存回调,因为一个promise实例可能会多次then,用数组就一个一个保存了
initValue() {
// 初始化值
this.PromiseResult = null // 终值
this.PromiseState = 'pending' // 状态
+ this.onFulfilledCallbacks = [] // 保存成功回调
+ this.onRejectedCallbacks = [] // 保存失败回调
}
resolve(value) {
// state是不可变的
if (this.PromiseState !== 'pending') return
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
// 执行保存的成功回调
+ while (this.onFulfilledCallbacks.length) {
+ this.onFulfilledCallbacks.shift()(this.PromiseResult)
+ }
}
reject(reason) {
// state是不可变的
if (this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState = 'rejected'
// 终值为传进来的reason
this.PromiseResult = reason
// 执行保存的失败回调
+ while (this.onRejectedCallbacks.length) {
+ this.onRejectedCallbacks.shift()(this.PromiseResult)
+ }
}
then(onFulfilled, onRejected) {
// 接收两个回调 onFulfilled, onRejected
// 参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调
onFulfilled(this.PromiseResult)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二哥回调
onRejected(this.PromiseResult)
+ } else if (this.PromiseState === 'pending') {
+ // 如果状态为待定状态,暂时保存两个回调
+ this.onFulfilledCallbacks.push(onFulfilled.bind(this))
+ this.onRejectedCallbacks.push(onRejected.bind(this))
+ }
}
3. 链式调用
then
支持链式调用,下一次then
执行受上一次then
返回值的影响,给大家举个例子:
// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => 2 * res, err => console.log(err))
.then(res => console.log(res), err => console.log(err))
// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err))
.then(res => console.log(res), err => console.log(err))
从上方例子,我们可以获取到几个知识点:
- then方法本身会返回一个新的Promise
- 如果返回值是promise对象,返回值为成功,新promise就是成功
- 如果返回值是promise对象,返回值为失败,新promise就是失败
- 如果返回值非promise对象,新promise对象就是成功,值为此返回值
咱们知道then是Promise上的方法,那如何实现then完还能再then呢?很简单,then执行返回一个Promise对象就行了,就能保证then完还能继续执行then
watermark2.jpg
代码实现
then(onFulfilled, onRejected) {
// 接收两个回调 onFulfilled, onRejected
// 参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
var thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = cb => {
try {
const x = cb(this.PromiseResult)
if (x === thenPromise) {
// 不能返回自身哦
throw new Error('不能返回自身。。。')
}
if (x instanceof MyPromise) {
// 如果返回值是Promise
// 如果返回值是promise对象,返回值为成功,新promise就是成功
// 如果返回值是promise对象,返回值为失败,新promise就是失败
// 谁知道返回的promise是失败成功?只有then知道
x.then(resolve, reject)
} else {
// 非Promise就直接成功
resolve(x)
}
} catch (err) {
// 处理报错
reject(err)
throw new Error(err)
}
}
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调
resolvePromise(onFulfilled)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二个回调
resolvePromise(onRejected)
} else if (this.PromiseState === 'pending') {
// 如果状态为待定状态,暂时保存两个回调
// 如果状态为待定状态,暂时保存两个回调
this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
}
})
// 返回这个包装的Promise
return thenPromise
}
4. 微任务
then
方法是微任务,所以我们需要让resolvePromise
函数异步执行
const resolvePromise = cb => {
setTimeout(() => {
try {
const x = cb(this.PromiseResult)
if (x === thenPromise) {
// 不能返回自身哦
throw new Error('不能返回自身。。。')
}
if (x instanceof MyPromise) {
// 如果返回值是Promise
// 如果返回值是promise对象,返回值为成功,新promise就是成功
// 如果返回值是promise对象,返回值为失败,新promise就是失败
// 谁知道返回的promise是失败成功?只有then知道
x.then(resolve, reject)
} else {
// 非Promise就直接成功
resolve(x)
}
} catch (err) {
// 处理报错
reject(err)
throw new Error(err)
}
})
}
其它方法
all
- 接受一个promise数组,数组中如有非promise项,则此项当做成功
- 如果所有promise都成功,则反悔成功结果数组
- 如果有一个promise失败,则返回这个失败结果
static all(promises) {
const result = [] // 保存成功值 的数组
let count = 0 // 判断是否调用完成
return new MyPromise((resolve, reject) => {
// 用于将成功回调添加进数组
const addData = (index, value) => {
result[index] = value // 收集 成功值
count++ // 同时计算成功值个数
if (count === promise.length) resolve(result) // 收集满了就执行resolve回调
}
// 循环获取promise
promises.forEach((promise, idx) => {
// 判断数组中是否有非Promise项
if (promise instanceof MyPromise) {
promise.then(res => {
// 将成功回调里的数据添加到 数组中
addData(idx, res)
}, err => {
reject(err) // 如果有一个错误,就执行 reject回调
})
} else {
// 非promise项当做成功 添加到数组中
addData(idx, promise)
}
})
})
}
race
- 接受一个Promise数组,数组中如有非Promise项,则此项当做成功
- 哪个Promise最快得到结果,就返回那个结果,无论成功失败
static race(promises){
return new MyPromise((resolve, reject)=>{
promises.forEach(promise=>{
if(promise instanceof MyPromise){
promise.then(res=>resolve(res),err=>reject(err))
}else{
resolve(promise)
}
})
})
}
allSettled
- 接受一个Promise数组,数组中如有非promise项,则当此项成功
- 把每个promise的结果,集合成数组返回
static allSettled(promises) {
const res = [] // 保存成功值 的数组
let count = 0 // 判断是否调用完成
return new MyPromise((resolve, reject) => {
// 用于将成功回调添加进数组
const addData = (status, value, index) => {
res[index] = {
status,
value
} // 收集 成功值
count++ // 同时计算成功值个数
if (count === promise.length) resolve(res) // 收集满了就执行resolve回调
}
// 循环获取promise
promises.forEach((promise, idx) => {
// 判断数组中是否有非Promise项
if (promise instanceof MyPromise) {
promise.then(res => {
// 将成功回调里的数据添加到 数组中
addData('fulfilled', res, idx)
}, err => {
addData('rejected', err, idx)
})
} else {
// 非promise项当做成功 添加到数组中
addData('fulfilled', promise, idx)
}
})
})
}
any
any与all相反
- 接受一个promise数组,数组中如有非promise项,则此项当做成功
- 如果有一个promise成功,则返回这个成功结果
- 如果所有promise都失败,则报错
static any(promises){
let count = 0
return new MyPromise((resolve,reject)=>{
promises.forEach((promise)=>{
promise.then(val=>{
resolve(val)
},err=>{
count++
if(count === promises.length){
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
最终代码
class MyPromise {
constructor(executor) {
// 初始化值
this.initValue()
// 初始化this指向
this.initBind()
try {
// 执行传进来的函数
executor(this.resolve, this.reject)
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e)
}
}
initBind() {
// 在不同的作用域下调用处理函数,会让处理函数中的this失去方向
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initValue() {
this.PromiseResult = null // 终值
this.PromiseState = 'pending' // 状态
this.onFulfilledCallbacks = [] // 保存成功回调
this.onRejectedCallbacks = [] // 保存失败回调
}
resolve(value) {
// state是不可变的
if (this.PromiseState != 'pending') return
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled'
// 终值为传进来的值
this.PromiseResult = value
// 执行保存的成功回调
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult)
}
}
reject(reason) {
// state是不可变的
if (this.PromiseState != 'pending') return
// 与resolve同理
this.PromiseState = 'rejected'
this.PromiseResult = reason
// 执行保存的失败回调
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult)
}
}
then(onFulfilled, onRejected) {
// 接收两个回调,参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
}
// 作为下一次返回的promise
let thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = cb => {
// 异步去执行回调函数
setTimeout(() => {
try {
const x = cb(this.PromiseState) // then中回调函数执行结果
// 回调函数执行的返回结果,不能是当前promise实例,因为这样永远都不会成功或者失败,所以应抛出一个错误
if (x === thenPromise) {
throw new Error('不能返回自身')
}
// 如果回调函数执行的返回结果是promise,那么应该取出promise的结果,作为promise2成功或者失败结果
if (x instanceof MyPromise) {
// 再次循环,获取promise2的结果
x.then(resolve, reject)
} else {
// 非Promise 就直接成功
resolve(x)
}
} catch (e) {
// 处理报错
reject(e)
throw new Error(e)
}
}, 0);
}
if (this.PromiseState === 'fulfilled') {
// 如果当前为成功状态,执行第一个回调函数
// 但是需要判断回调函数执行完成后的结果,所以需要将回调函数包装一下
resolvePromise(onFulfilled)
} else if (this.PromiseState === 'rejected') {
// 如果当前为失败状态,执行第二个回调函数
resolvePromise(onRejected)
} else if (this.PromiseState === 'pending') {
// 如果状态为待定状态,暂时保存两个回调
// 如果状态为待定状态,暂时保存两个回调
this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
}
})
return thenPromise
}
static all(promises) {
const result = [] // 保存成功值 的数组
let count = 0 // 判断是否调用完成
return new MyPromise((resolve, reject) => {
// 用于将成功回调添加进数组
const addData = (index, value) => {
result[index] = value // 收集 成功值
count++ // 同时计算成功值个数
if (count === promise.length) resolve(result) // 收集满了就执行resolve回调
}
// 循环获取promise
promises.forEach((promise, idx) => {
// 判断数组中是否有非Promise项
if (promise instanceof MyPromise) {
promise.then(res => {
// 将成功回调里的数据添加到 数组中
addData(idx, res)
}, err => {
reject(err) // 如果有一个错误,就执行 reject回调
})
} else {
// 非promise项当做成功 添加到数组中
addData(idx, promise)
}
})
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
if (promise instanceof MyPromise) {
promise.then(res => resolve(res), err => reject(err))
} else {
resolve(promise)
}
})
})
}
static allSettled(promises) {
const res = [] // 保存成功值 的数组
let count = 0 // 判断是否调用完成
return new MyPromise((resolve, reject) => {
// 用于将成功回调添加进数组
const addData = (status, value, index) => {
res[index] = {
status,
value
} // 收集 成功值
count++ // 同时计算成功值个数
if (count === promise.length) resolve(res) // 收集满了就执行resolve回调
}
// 循环获取promise
promises.forEach((promise, idx) => {
// 判断数组中是否有非Promise项
if (promise instanceof MyPromise) {
promise.then(res => {
// 将成功回调里的数据添加到 数组中
addData('fulfilled', res, idx)
}, err => {
addData('rejected', err, idx)
})
} else {
// 非promise项当做成功 添加到数组中
addData('fulfilled', promise, idx)
}
})
})
}
static any(promises) {
let count = 0
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(val => {
resolve(val)
}, err => {
count++
if (count === promises.length) {
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
网友评论