如何手写Promise
一、开始手写
1.Promise首先是个类,因为它可以实例化,我们使用es6提供的class来模拟它,当然构造函数也行,但是写的太烦了,算了算了
2.Promise接受一个立即执行的函数,这个函数又接受两个参数,一个resolve,一个reject
3.Promise包含三种状态,初始状态等待(pending),成功状态(fulFilled),失败状态(rejected)
4.Promise的状态由resolve和reject改变
// 用常量定义三个状态,避免单词写错的小尴尬事件
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
resolve = () => {
this.status = FULFILLED
}
reject = () => {
this.status = REJECTED
}
}
5.Promise的状态一经改变,就不能再变化,状态已经锁定了
6.Promise的then方法接受两个函数作为参数,一个成功回调函数,一个失败回调函数,两个函数也接受一个参数,分别表示成功的结果和失败的原因,这两个值由resolve和reject分别传递过来
// 声明了两个参数value和reason来保存成功和失败的结果
// 方便then方法的成功与失败回调使用
// 而Promise的状态改变之后便锁定也很容易实现,在改变status之前判断status是否等于pending
// 如果status !== pending,则代表status已经发生了改变,直接return
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
}
then = (successCallback, failCallback) => {
if (this.status === FULFILLED) {
successCallback(this.value)
} else {
failCallback(this.reason)
}
}
}
let p = new MyPromise((res, rej) => {
console.log(111);
res("success")
rej("fail")
})
// 只会执行成功回调
p.then(value => {
console.log(value);
}, err => {
console.log(err);
})
7.Promise是用来处理异步的,那么我们试着加入异步的逻辑,怎么加?如果执行到then时,status === pending,将then里的方法储存起来,在resolve或reject的最后执行就行啦,类似于回调函数,类似于哈,但不是,你就这么想就行了
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
// 新增了成功回调
successCallback = undefined
// 新增了失败回调
failCallback = undefined
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 执行异步逻辑
this.successCallback && this.successCallback(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 执行异步逻辑
this.failCallback && this.failCallback(this.reason)
}
then = (successCallback, failCallback) => {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallback(this.reason)
} else {
// 此时status为pending,说明处于异步情况,我们需要将成功回调和失败回调存储起来
// 在resolve()或reject()最后的地方执行
this.successCallback = successCallback
this.failCallback = failCallback
}
}
}
// 首先then执行了,但是因为res在两秒后才会执行,所以then里的status===pending
// 所以then里的回调不会执行,而是先储存起来
// 2秒后,res执行,成功回调在res的最后执行
// 这就是Promise通过then执行异步逻辑的原因,将同步代码保存起来,放在异步代码的最后执行
let p = new MyPromise((res, rej) => {
setTimeout(() => {
res("success")
}, 2000)
})
p.then(value => {
console.log(value);
}, err => {
console.log(err);
})
8.Promise的then方法可以多次调用,每次调用的方法可能都不相同,所以我们需要将所有的成功回调与失败回调保存起来全部保存起来,在status改变之后,遍历调用,当然同步代码不影响,因为直接执行了,异步代码因为是保存着的,所以现在我们要用一个数组给他包起来了
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
// 新增成功回调集合
successCallbackList = []
// 新增失败回调集合
failCallbackList = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 执行异步逻辑
// this.successCallback && this.successCallback(this.value)
// 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
while (this.successCallbackList.length) this.successCallbackList.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 执行异步逻辑
// this.failCallback && this.failCallback(this.reason)
while (this.failCallbackList.length) this.failCallbackList.shift()(this.value)
}
then = (successCallback, failCallback) => {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallback(this.reason)
} else {
// 将回调函数保存在数组里,遍历执行
this.successCallbackList.push(successCallback)
this.failCallbackList.push(failCallback)
}
}
}
let p = new MyPromise((res, rej) => {
setTimeout(() => {
res("success")
}, 2000)
})
p.then(value => {
console.log(value);
}, err => {
console.log(err);
})
p.then(value => {
console.log(222);
}, err => {
console.log(err);
})
p.then(value => {
console.log(333);
}, err => {
console.log(err);
})
9.Promise的链式调用,是解决回调地狱的关键。你知道为啥能链式调用吗?现在我们知道Promise对象可以执行.then,所以每次.then过后就返回一个新的Promise就行了。
10.下一个then的参数就是上一个Promise的返回,但是返回分两种,如果是普通值返回,直接返回就可以了,但是如果返回的是一个Promise对象,那么就得执行这个Promise,等待Promise的状态改变再返回这个Promsie的返回值了
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
// 成功回调集合
successCallbackList = []
// 失败回调集合
failCallbackList = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 执行异步逻辑
// 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
while (this.successCallbackList.length) this.successCallbackList.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 执行异步逻辑
while (this.failCallbackList.length) this.failCallbackList.shift()(this.reason)
}
then = (successCallback, failCallback) => {
// 这里实例化了一个promise2,并且返回它,以供后面链式调用
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let result = successCallback(this.value)
// 判断result的类型
judgeResult(result, resolve, reject)
} else if (this.status === REJECTED) {
let result = failCallback(this.reason)
// 判断result的类型
judgeResult(result, resolve, reject)
} else {
this.successCallbackList.push(successCallback)
this.failCallbackList.push(failCallback)
}
})
return promise2
}
}
/**
* 判断result,如果是个值,那就直接resolve
* 如果是个Promise,那需要执行.then(),根据.then的结果返回
*/
function judgeResult(result, resolve, reject) {
if (result instanceof MyPromise) {
result.then(value => resolve(value), error => reject(error))
} else {
resolve(result)
}
}
p.then(value => {
console.log(value);
return "p1--success"
}).then(value => {
console.log(value);
return new MyPromise((res, rej) => {
rej("p2--fail")
})
}).then(undefined, err => {
console.log(err);
return new MyPromise((res, rej) => {
setTimeout(()=> {
res("p3--async")
}, 1000)
})
}).then(value => {
console.log(value);
})
11.then返回的如果是个Promise,那么这个返回不能是自己,否则就死循环了,这里也要处理一下
value = undefined
// 失败的原因
reason = undefined
// 成功回调集合
successCallbackList = []
// 失败回调集合
failCallbackList = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 执行异步逻辑
// 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
while (this.successCallbackList.length) this.successCallbackList.shift()()
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 执行异步逻辑
while (this.failCallbackList.length) this.failCallbackList.shift()()
}
then = (successCallback, failCallback) => {
// 这里实例化了一个promise2,并且返回它,以供后面链式调用
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
setTimeout(() => {
let result = successCallback(this.value)
// 判断result的类型
judgeResult(promise2, result, resolve, reject)
}, 0)
} else if (this.status === REJECTED) {
// 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
setTimeout(() => {
let result = failCallback(this.reason)
// 判断result的类型
judgeResult(promise2, result, resolve, reject)
}, 0)
} else {
this.successCallbackList.push(() => {
// 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
setTimeout(() => {
let result = successCallback(this.value)
// 判断result的类型
judgeResult(promise2, result, resolve, reject)
}, 0)
})
this.failCallbackList.push(() => {
// 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
setTimeout(() => {
let result = failCallback(this.reason)
// 判断result的类型
judgeResult(promise2, result, resolve, reject)
}, 0)
})
}
})
return promise2
}
}
/**
* 判断result,如果是个值,那就直接resolve
* 如果是个Promise,那需要执行.then(),根据.then的结果返回
*/
function judgeResult(promise2, result, resolve, reject) {
if(promise2 === result) {
return reject("别自己返回自己啊喂!!!")
}
if (result instanceof MyPromise) {
result.then(value => resolve(value), error => reject(error))
} else {
resolve(result)
}
}
p.then(value => {
console.log(value);
return "p1--success"
}).then(value => {
console.log(value);
return new MyPromise((res, rej) => {
rej("p2--fail")
})
}).then(undefined, err => {
console.log(err);
return new MyPromise((res, rej) => {
setTimeout(()=> {
res("p3--async")
}, 1000)
})
}).then(value => {
console.log(value);
})
// 测试不能返回自己
let p2 = p.then((value) => {
console.log(value);
return p2
})
p2.then((value)=> {
console.log(value)
}, (error) => {
console.log(error)
})
12.then方法的参数不是一个函数时,会自动转换成一个value => value的方法
13.Promise中,每个地方产生的错,最终都会被捕获,所以现在把该捕获错误的地方都捕一捕
// 如何捕获失败,用try/catch,在哪里捕获?在你认为会错的地方😀
class MyPromise {
constructor (executor) {
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
// 成功回调集合
successCallbackList = []
// 失败回调集合
failCallbackList = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 执行异步逻辑
// 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
while (this.successCallbackList.length) this.successCallbackList.shift()()
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 执行异步逻辑
while (this.failCallbackList.length) this.failCallbackList.shift()()
}
then = (successCallback, failCallback) => {
// 判断successCallback和failCallback是不是函数,如果不是,转化成一个函数
successCallback = typeof successCallback === 'function' ? successCallback : value => value
failCallback = typeof failCallback === 'function' ? failCallback : value => value
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
try {
setTimeout(() => {
let result = successCallback(this.value)
// 判断result的类型
judgeResult(result, resolve, reject)
}, 0)
} catch (error) {
reject(error)
}
} else if (this.status === REJECTED) {
try {
setTimeout(() => {
let result = failCallback(this.reason)
// 判断result的类型
judgeResult(result, resolve, reject)
}, 0)
} catch (error) {
reject(error)
}
} else {
this.successCallbackList.push(() => {
try {
setTimeout(() => {
let result = successCallback(this.value)
// 判断result的类型
judgeResult(result, resolve, reject)
}, 0)
} catch (error) {
reject(error)
}
})
this.failCallbackList.push(() => {
try {
setTimeout(() => {
let result = failCallback(this.reason)
// 判断result的类型
judgeResult(result, resolve, reject)
}, 0)
} catch (error) {
reject(error)
}
})
}
})
return promise2
}
}
/**
* 判断result,如果是个值,那就直接resolve
* 如果是个Promise,那需要执行.then(),根据.then的结果返回
*/
function judgeResult(promise2, result, resolve, reject) {
throw(new Error("judgeResult error"))
if(promise2 === result) {
return reject("别自己返回自己啊喂!!!")
}
if (result instanceof MyPromise) {
result.then(value => resolve(value), error => reject(error))
} else {
resolve(result)
}
}
let p = new MyPromise((res, rej) => {
res("success")
})
p.then().then("b").then(value => console.log(value))
14.Promise包含几个重要的静态方法,all、race、resolve、catch、finally,现在我们实现一下
// Promise.all 故名思意,就是等全部,全部成功之后,返回一个Promise对象,成功回调全部返回的数组
// 如果有失败,则会返回一个Promise对象,失败回调第一个失败的返回
static all(array) {
try {
if (!(array instanceof Array)) throw(new Error("请传入一个数组好吗"))
if (array.length == 0) throw(new Error("请不要传入一个空数组好吗"))
let arr = []
return new MyPromise((res, rej) => {
// 这里有个坑,遍历的里面是异步,所以在最后res(arr)会有问题
// 所以每次arr.push之后,就比较一下两个arr的长度,长度相等说明已经遍历完了,可以执行res(arr)了
for(let item of array) {
if (item instanceof MyPromise) {
item.then(value=> {
arr.push(value)
}, error => {
rej(error)
})
} else {
arr.push(item)
if(arr.length == array.length) res(arr)
}
}
// return res(arr)
})
} catch (error) {
console.log(error);
}
}
// Promise.race故名思意,竞争,看谁先结束,返回的Promise就用谁的返回
static race(array) {
try {
if (!(array instanceof Array)) throw(new Error("请传入一个数组好吗"))
if (array.length == 0) throw(new Error("请不要传入一个空数组好吗"))
return new MyPromise((res, rej) => {
for(let item of array) {
if (item instanceof MyPromise) {
item.then(value=> {
res(value)
}, error => {
rej(error)
})
} else {
res(item)
}
}
})
} catch (error) {
console.log(error);
}
}
// Promise.resolve 参数如果不是Promise对象,直接返回一个成功回调为参数的Promise对象
// 如果参数是Promise对象,那直接返回参数即可
static resolve(params) {
try {
if(params instanceof MyPromise) {
return params
} else {
return new MyPromise(res => {
res(params)
})
}
} catch (error) {
console.log(error);
}
}
// Promise.catch就是一个没有成功回调的then
static catch(failCallback) {
return this.then(null, failCallback)
}
// Promise.finally
// 不管成功还是失败都要执行
// 回调函数中不包含当前Promise的返回值,也就是callback不传递参数
// 但是会把当前Promise的返回值return出去,所以调用this.then,获取当前Promise的返回值
// 如果finally返回一个Promise,会执行,但是仍然返回当前Promise的返回值,而不是fianlly返回的Promise的返回值
static finally(callback) {
this.then(value => {
this.resolve(callback()).then(() => value)
}, error => {
this.resolve(callback()).then(() => {
throw error
})
})
}
p1.then(()=> {
return "1111"
}).finally(value => {
console.log(value); // undefined
return new MyPromise(res => {
res("2222")
})
}).then(value=> {
console.log(value); // "1111"
})

浙公网安备 33010602011771号