一步一步
1、首先来个架子,几大件先摆上,首先是状态三个,方法两个(resolve和reject),then方法。
//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
constructor(exec){
//状态初始化为pending
this.state = PENDING
//状态resolve变为fulfilled,存储结果
this.value = ''
//状态reject后,存储原因
this.reson = ''
let resolve = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成fulfilled
this.state = FULFILLED
// 将结果记录
this.value = val
}
}
let reject = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成rejected
this.state = REJECTED
// 将原因记录
this.reson = val
}
}
//立即执行exec,放在try catch里面是为了兼容运行出错情况
try {
exec(resolve,reject)
} catch (error) {
//出错直接reject就行了
reject(error)
}
}
// 还得有个then方法
then(onFulfilled, onRejected){
}
}
2、接下来开始实现then方法
then接受两个参数,一个成功的回调(onFulfilled),一个失败的(onRejected),如果状态是fulfilled,就会执行成功的回调,如果是失败的,就会执行失败的,所以最简单的就是这种:
// 还得有个then方法
then(onFulfilled, onRejected){
if(this.state == FULFILLED){
onFulfilled(this.value)
}else if(this.state == REJECTED){
onRejected(this.reson)
}
}
一个相当简单的就实现啦。简单测试一下
let p = new myPromise((resolve,reject) => {
// resolve(111111)
reject('出错了')
})
p.then(res => {
console.log(res)
},err => {
console.log(err)//出错了
})
但是这样会有一个问题,当promise里是异步的时候,是不能返回结果的,如下
let p = new myPromise((resolve,reject) => {
// resolve(111111)
// reject('出错了')
setTimeout(() => {
resolve('异步执行')
}, 3000);
})
p.then(res => {
console.log(res)
},err => {
console.log(err)
})
此时发现then中并没有成功打印出所希望的res,也就是‘异步执行’这几个字,原因是因为上边实现的then方法执行的时候,此时的promise状态还是pending呢,还没有来得及变化。所以接下来要丰富我们的then方法。
3、支持异步
思路大概是,当执行then的时候,发现现在的状态还是pending的话,就将回调函数存储起来,等真正改变状态,执行resolve或者reject的时候再去执行,所以这里需要需要:
- class里声明两个数组,来存储回调函数,这里我命名为resolveList和rejectList
- then中判断状态为pending的时候,将回调函数存储起来
- 在resovle和reject方法中,执行调用存储的函数
最后整理的代码如下
//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
constructor(exec){
//状态初始化为pending
this.state = PENDING
//状态resolve变为fulfilled,存储结果
this.value = ''
//状态reject后,存储原因
this.reson = ''
//这俩数组存then中的回调函数
this.resolveList = []
this.rejectList = []
let resolve = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成fulfilled
this.state = FULFILLED
// 将结果记录
this.value = val
// 执行一下可能存在的异步存储的函数
this.resolveList.forEach(item => {
item(this.value)
})
}
}
let reject = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成rejected
this.state = REJECTED
// 将原因记录
this.reson = val
// 执行一下可能存在的异步存储的函数
this.rejectList.forEach(item => {
item(this.reson)
})
}
}
//立即执行exec,放在try catch里面是为了兼容运行出错情况
try {
exec(resolve,reject)
} catch (error) {
//出错直接reject就行了
reject(error)
}
}
// 还得有个then方法
then(onFulfilled, onRejected){
if(this.state == FULFILLED){
onFulfilled(this.value)
}else if(this.state == REJECTED){
onRejected(this.reson)
}else if(this.state == PENDING){
this.resolveList.push(onFulfilled)
this.rejectList.push(onRejected)
}
}
}
let p = new myPromise((resolve,reject) => {
// resolve(111111)
// reject('出错了')
setTimeout(() => {
resolve('异步执行')
}, 3000);
})
p.then(res => {
console.log(res)//成功打印了‘异步执行’
},err => {
console.log(err)
})
这里有一个可能没什么用的点解释一下,就是为什么要用数组(resolveList和rejectList)去存储,而不用变量去存储,是为了解决下边这种情况
let p = new myPromise((resolve,reject) => {
// resolve(111111)
// reject('出错了')
setTimeout(() => {
resolve('异步执行')
}, 3000);
})
p.then(res => {
console.log(res)
},err => {
console.log(err)
})
p.then(res => {
console.log(res+1)
})
这种时候如果用变量的话,第二个的成功的回调就会把第一个成功的回调冲掉,所以要用数组都存储下来。
到这里就大体实现了一个简单的promise,考虑的都是理想情况,比如then里边传的都是函数,没有兼容其他的什么类型。
下面开始写链式调用
4、链式调用then
首先要明白,链式调用前一个then要返回一个promise才能实现连续的.then,所以我们需要改造一下then方法,让他返回一个promise,并且声明一个处理函数resolvePromise作为集中的对于promise的处理,下边是完整的代码
//弄点变量当作状态,假装很高级的样子
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 开始了
class myPromise{
constructor(exec){
//状态初始化为pending
this.state = PENDING
//状态resolve变为fulfilled,存储结果
this.value = ''
//状态reject后,存储原因
this.reson = ''
//这俩数组存then中的回调函数
this.resolveList = []
this.rejectList = []
let resolve = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成fulfilled
this.state = FULFILLED
// 将结果记录
this.value = val
// 执行一下可能存在的异步存储的函数
this.resolveList.forEach(item => {
item(this.value)
})
}
}
let reject = (val) => {
//状态只能变一次,所以这里判断一下,如果只有pending的时候才执行
if(this.state == PENDING){
// 状态变成rejected
this.state = REJECTED
// 将原因记录
this.reson = val
// 执行一下可能存在的异步存储的函数
this.rejectList.forEach(item => {
item(this.reson)
})
}
}
//立即执行exec,放在try catch里面是为了兼容运行出错情况
try {
exec(resolve,reject)
} catch (error) {
//出错直接reject就行了
reject(error)
}
}
// 还得有个then方法
then(onFulfilled, onRejected){
// if(this.state == FULFILLED){
// onFulfilled(this.value)
// }else if(this.state == REJECTED){
// onRejected(this.reson)
// }else if(this.state == PENDING){
// this.resolveList.push(onFulfilled)
// this.rejectList.push(onRejected)
// }
//如果是空或者不是函数,替换成直接返回value或者reson的函数,这样链式的时候如果前边的没有回调函数,也能够将值传递过去
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
let promise2 = new myPromise((reslove,reject) => {
if(this.state == FULFILLED){
setTimeout(() => {
//异步的,所以用settimeout,而且不用之后使用promise2的时候也会报错
try {
//x为then的成功的回调函数返回的结果
let x = onFulfilled(this.value)
//resolvePromise为对于promise2的处理
resolvePromise(promise2,x,reslove,reject)
} catch (error) {
reject(error)
}
},0)
}else if(this.state == REJECTED){
setTimeout(() => {
try {
//x为then的失败回调函数返回的结果
let x = onRejected(this.reson)
resolvePromise(promise2,x,reslove,reject)
} catch (error) {
reject(error)
}
},0)
}else if(this.state == PENDING){
this.resolveList.push(() => {
setTimeout(() => {
try {
//x为then的成功的回调函数返回的结果
let x = onFulfilled(this.value)
resolvePromise(promise2,x,reslove,reject)
} catch (error) {
reject(error)
}
}, 0);
})
this.rejectList.push(() => {
setTimeout(() => {
try {
//x为then的失败回调函数返回的结果
let x = onRejected(this.reson)
resolvePromise(promise2,x,reslove,reject)
} catch (error) {
reject(error)
}
},0)
})
}
})
return promise2
}
}
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
reject('陷入了死循环')
return
}
//如果是对象或者函数
if(x !== null && (typeof x === 'object' || typeof x === 'function')){
let then = x.then
if(then && typeof then == 'function'){
// 如果x是个promise,就去执行他的then方法,然后把结果处理出来,当作去往链式调用的结果
try {
then.call(x,res => {
//防止x.then执行出来之后结果还是返回了一个promise,所以递归执行一下resolvePrimise
resolvePromise(promise2,res,resolve,reject)
})
} catch (error) {
reject(err)
}
}else{
resolve(x)
}
}else{
//如果不是对象,直接resolve
resolve(x)
}
}
//自己的测试代码
let p = new myPromise((resolve,reject) => {
setTimeout(() => {
resolve('异步执行')
}, 3000);
})
p.then(res => {
console.log(res)//异步执行
return new myPromise((resolve,reject) => {
setTimeout(()=>{
resolve(2)
},3000)
})
},err => {
console.log(err)
}).then(res => {
console.log(res+2) //4
})
p.then(res => {
console.log(res+1)//异步执行1
})
promise一些方法的实现
1、promise.resolve
myPromise.resolve = (val) => {
//如果是promise的话,直接返回,不是就封装一下
if(val.then&& typeof val.then == 'function'){
return val
}else{
return new myPromise((resolve,reject) => {
resolve(val)
})
}
}
2、all
myPromise.all = function(arr = []){
let idx = 0//记录产生了多少个结果
let len = arr.length//记录数组长度
let resArr = [] // 存放promise执行的结果
return new myPromise((resolve,reject) => {
arr.forEach((item,index) => {
myPromise.resolve(item).then(res => {
//保证传入顺序对应结果顺序
resArr[index] = res
idx++
//如果两个值相等的时候,就说明所有的传入的promise都已经执行完毕,可以返回结果了
if(idx == len){
resolve(resArr)
}
},error => {
reject(error)
})
})
})
}
3、race
myPromise.race = function(arr = []){
return new myPromise((resolve,reject) => {
arr.forEach((item,index) => {
myPromise.resolve(item).then(res => {
//谁快直接返回谁就行了
resolve(res)
},error => {
reject(error)
})
})
})
}
就先写这么多,简略的原理实现,有些极端情况并没有考虑,仅供参考,欢迎交流指正~,yeah!