- promise源码解析之手写源码
- 如何实现手写promise那我们必须要了解a+规范,在上一节,我们已经将a+规范简单的梳理了一遍,下面我们带着a+规范,将promise手写一遍逻辑
- *规范-:*需要定义三种状态—pedding/fulfiled/reject
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
- 已经定义好了三种状态,接下来需要对状态进行初始化
class ModelPromise{
constructor(callback){
this.status = PENDING // 状态初始化
this.value = null //成功后参数值
this.reason = null // 失败后的参数值
}
}
- 上面已经做好了前期准备,接下来就需要知道,进行状态机的改变,三种状态:pending, fulfilled, rejected,只有pending可以改变,其他两种皆不可改变,所以我们需要对promise的状态进行改变,通过resolve或者reject方法进行改变,那就需要判断status值是不是pedding,只需要在pendding状态下才可以变化;
class ModelPromise{
constructor(callback){
try {
// 执行回调
callback(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(value){
if(this.status === PENDING){
this.value = value // 先更新value
this.status = FULFILLED // 在更新状态
}
}
reject(reason){
if(this.status === PENDING){
this.reason = reason
this.status = REJECTED
}
}
}
- 上面的方法写的基本都是同步构造函数,那接下来如何实现
.then
函数这也是个异步微任务,首先我们也得知道then方法存在两个回调onFulfilled
和onRejected
回调,这个回调只能被执行一次在then方法里实现一个微任务方法
- 4.1先判断
onFulfilled
和onRejected
是不是函数,不是函数,对值进行透传
then(onFullFiled, onRejected){
const onRealFullFiled = this.isFunction(onFullFiled) ?onFullFiled:(value)=>value
const onRealRejected = this.isFunction(onRejected)?onRejected:(reason)=>{ throw reason }
}
- 4.2 规范中,需要返回一个新的promise,先根据状态status值,调用对应的状态方法
then(onRealFullFiled, onRealRejected){
...
const promise2 = new ModelPromise((resolve, reject)=>{
switch (this.status){
case FULFILLED:{
onRealFullFiled()
break;
}
case REJECTED:{
onRealRejected()
break;
}
}
})
return promise2
}
- 4.3 当状态还没有到达最终态时,这个我们需要定义一个队列进行存储,然后监听状态值,执行队列里的对应的方法
fulFiledList = []
rejectList = []
#status = PENDING
get(){}
set(){} //监听状态值的变化
then(onRealFullFiled, onRealRejected){
...
const promise2 = new ModelPromise((resolve, reject)=>{
switch (this.status){
case FULFILLED:{
onRealFullFiled()
break;
}
case REJECTED:{
onRealRejected()
break;
}
case PENDING:{
this.fulFiledList.push(onMicroTaskRealFullFiled)
this.rejectList.push(onMicroTaskRealReject)
break;
}
default:{
break;
}
}
})
return promise2
}
- 4.4 通过监听状态进行执行队列,采用getter 和setter方法进行监听状态值的变化
...
#status = PENDING
get(){
return this.#status
}
set(value){ //监听状态值的变化
this.value = value
switch(value){
case FULFILLED:{
this.fulFiledList.forEach(fn=>{
fn(this.value)
})
break;
}
case REJECTED:{
this.rejectList.forEach(fn=>{
fn(this.reason)
})
break;
}
default:{
break;
}
}
}
- 4.5 现在目前都还是同步,加入异步方法通过
setTimeout
或者queueMicrotask
进行异步执行
then(onFullFiled, onRejected){
...
const promise2 = new ModelPromise((resolve, reject)=>{
// 微任务
const onMicroTaskRealFullFiled = ()=>{
queueMicrotask(()=>{
try {
onRealFullFiled(this.value)
} catch (error) {
reject(error)
}
})
}
const onMicroTaskRealReject = ()=>{
queueMicrotask(()=>{
try {
onRealRejected(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
switch (this.status){
// 同4.3
...
}
})
return promise2
}
- 4.6 到目前为止,简易的promise已经处理的差不多了,当然还有
onFulfilled
和onRejected
这个两个回调函数处理,和then方法新生成的promise进行处理,处理新生成的Promise和x(回调返回值),判断这两个值的关系进行,如果x是一个promise实例,则进行进行递归解析promise,直到不再是promise为止;判断x是一个对象或者方法,进行解析,加入标志进行判断避免多次执行回调; - 4.7 返回promise进行链式调用
- catch方法,这个就简单了,通过调用then防范实现
catch(onReject){
return this.then(null, onReject)
}
- 接下来为大家实现两个race和all方法,通过promise使用,我们都知道这两个是静态方法
- 6.1 race方法:只要其中有一个promise通过就可执行
static race(values){
return new ModelPromise((resolve, reject)=>{
if(values.length === 0){
return resolve()
}
for(let i = 0; i<values.length;i++){
ModelPromise.resolve(values[i]).then(res=>{
return resolve(value);
}, (reason)=>{
return reject(reason)
})
}
})
}
- 6.2 all方法:需要所有的promise执行通过就行
static all(list){
if(list.length===0){
return new ModelPromise((resolve)=>resolve())
}
return new ModelPromise((resolve)=>{
let values = []
for (let i= 0;i<list.length;i++){
if(list[i] instanceof ModelPromise){
list[i].then(res=>{
values.push(res)
if(values.length === i+1){
resolve(values)
}
})
}
else{
queueMicrotask(()=>{
values.push(list[i])
if(values.length === i+1){
resolve(values)
}
})
}
}
})
}
- 总结:promise他是then方法后返回一个新的promise实例跟new 构造函数的promise不是同一个实例,里面函数队列实现,为了实现同一个实例的调用一个then方法,关键区别promise生成新的实例而已。