Promise实现

207 阅读3分钟

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)

Promise对象的状态改变,只有两种可能:从pending->fulfilled或pending->rejected,一旦状态改变,结果不会再变

缺点

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
第一步基本实现
function Promise(executor){
    this.status = 'pedding'
    this.value = undefined
    function resolve(data){
        if(this.status !== 'pedding') return
        this.status = 'fulfilled'
        this.value = data
    }
    function reject(data){
        if(this.status !== 'pedding') return
        this.status = 'rejected'
        this.value = data
    }
    try{
        executor(resolve.bind(this), reject.bind(this))
    }catch(err){
        reject.bind(this, err)
    }
}

Promise.prototype.then = function(onFulfilled, onRejected){
    if(this.status === 'fulfilled'){
        onFulfilled(this.value)
    }
    if(this.status === 'rejected'){
        onRejected(this.value)
    }
}

let p  = new Promise((resolve, reject) => {
    resolve(100)
})
p.then(data => {
    console.log(data) //打印100
})
加入异步执行

此时无法打印结果,因为Promise会立即执行,then方法中status依然为pending

let p  = new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve(100)
      }, 100)
})
p.then(data => {
    console.log(data) //无法打印
})

改进后,在then中先将回调放入列队中,等状态改变后执行

function Promise(executor){
    this.status = 'pedding'
    this.value = undefined
    this.fulfilledFunc = []
    this.rejectedFunc = []

    function resolve(data){
        if(this.status !== 'pedding') return
        this.status = 'fulfilled'
        this.value = data
        this.fulfilledFunc.forEach(item => item())
    }
    function reject(data){
        if(this.status !== 'pedding') return
        this.status = 'rejected'
        this.value = data
        this.rejectedFunc.forEach(item => item())
    }
    try{
        executor(resolve.bind(this), reject.bind(this))
    }catch(err){
        reject.bind(this, err)
    }
}

Promise.prototype.then = function(onFulfilled, onRejected){
    if(this.status === 'pedding'){
        this.fulfilledFunc.push(() => {
            setTimeout(() => {
                onFulfilled(this.value)
            },0)
        })
        this.rejectedFunc.push(() => {
            setTimeout(() => {
                onRejected(this.value)
            },0)
        })
    }
    if(this.status === 'fulfilled'){
        setTimeout(() => {
            onFulfilled(this.value)
        },0)
    }
    if(this.status === 'rejected'){
        setTimeout(() => {
            onRejected(this.value)
        },0)
    }
}

let p  = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(100)//1秒后打印
    }, 1000)
})

p.then(data => {
    console.log(data)
})

then

then方法是定义在Promise.prototype上,第一个参数是resolve状态的回调函数,第二个参数(可选)是reject状态的回调函数

then方法返回的是一个新的Promise实例,因此可以采用链式写法

Promise.prototype.then = function(onFulfilled, onRejected){
   return new Promise((resolve, reject) => {
        if(this.status === 'pedding'){
            this.fulfilledFunc.push(() => {
                setTimeout(() => {
                    try{
                        onFulfilled(this.value)
                    }catch(e){
                        reject(e)
                    }
                },0)
            })
            this.rejectedFunc.push(() => {
                setTimeout(() => {
                    try{
                        onRejected(this.value)
                    }catch(e){
                        reject(e)
                    }
                },0)
            })
        }
        if(this.status === 'fulfilled'){
            setTimeout(() => {
                try{
                    onFulfilled(this.value)
                }catch(e){
                    reject(e)
                }
            },0)
        }
        if(this.status === 'rejected'){
            setTimeout(() => {
                try{
                    onRejected(this.value)
                }catch(e){
                    reject(e)
                }
            },0)
        }
   })
}

试试链式调用

let p  = new Promise((resolve, reject) => {
    resolve(100)
})


let p2 = p.then(data => {
    console.log(123)
   return data
}).then(data => {
    console.log(data)
})


发现第一个then输出了 第二个then没有执行,因为我们的then方法没有将返回值向下一个promise传递

then方法片段
 if(this.status === 'fulfilled'){
      setTimeout(() => {
          try{
          	//获取第一个then的返回值,没有返回值则为undefined
              let x= onFulfilled(this.value)
              //向下一个then传递
              resolvePromise(x, resolve, reject)
          }catch(e){
              reject(e)
          }
      },0)
}
resolvePromise
function resolvePromise(x, resolve, reject) {
    if(x != null && (typeof x === 'object') || (typeof x === 'function')){
    } else {  
        resolve(x);
    }
}

在第一个then中返回promise

let p  = new Promise((resolve, reject) => {
      resolve(100)
})
let p2 = p.then(data => {
    return new Promise((resolve, reject) => {
        resolve(1000)
    })
})
p2.then(data => {
	console.log(data)
}) 

发现没有返回,我们继续完善resolvePromise

function resolvePromise(x, resolve, reject) {
    if(x != null && (typeof x === 'object') || (typeof x === 'function')){
        if(typeof x.then === 'function'){
            x.then(data => {
                resolve(data)
            }, err => {
                reject(err)
            })
        }else{
            resolve(x)
        }
    } else {  
        resolve(x);
    }
}

此时可以返回了,我们继续promise resolve promise

let p  = new Promise((resolve, reject) => {
      resolve(100)
})
let p2 = p.then(data => {
    return new Promise((resolve, reject) => {
         resolve(new Promise((resolve, reject) => {
                resolve(1000)
          }))
    })
})
p2.then(data => {
	console.log(data)
}) 

此时没有返回值了,我们继续完善resolvePromise

function resolvePromise(x, resolve, reject) {
    if(x != null && (typeof x === 'object') || (typeof x === 'function')){
          if(typeof x.then === 'function'){
              x.then(data => {
                  //递归执行
                  resolvePromise(data, resolve, reject)
              }, err => {
                  reject(err)
              })
          }else{
              resolve(x)
          }
      }else {  
          resolve(x);
    }
}

好了,我们完善一下then

Promise.prototype.then = function(onFulfilled, onRejected){
     return new Promise((resolve, reject) => {
        if(this.status === 'pedding'){
            this.fulfilledFunc.push(() => {
                setTimeout(() => {
                    try{
                        let x = onFulfilled(this.value)
                        resolvePromise(x, resolve, reject);
                    }catch(e){
                        reject(e)
                    }
                },0)
            })
            this.rejectedFunc.push(() => {
                setTimeout(() => {
                    try{
                        let x = onRejected(this.value)
                        resolvePromise(x, resolve, reject);
                    }catch(e){
                        reject(e)
                    }
                },0)
            })
        }
        if(this.status === 'fulfilled'){
            setTimeout(() => {
                try{
                    let x = onFulfilled(this.value)
                   
                    resolvePromise(x, resolve, reject);
                }catch(e){
                    reject(e)
                }
            },0)
        }
        if(this.status === 'rejected'){
            setTimeout(() => {
                try{
                    let x = onRejected(this.value)
                    resolvePromise(x, resolve, reject);
                }catch(e){
                    reject(e)
                }
            },0)
        }
   })
}

Promise.all

Promise.all等参数中的promise都fulfilled了返回结果,如果有一个状态rejected结果则为rejected

Promise.all = function(arr){
    return new Promise((resolve, reject) => {
       const list = []
        arr.forEach((item, index ) => {
            item.then(data => {
                    list.push(data)
                    if(list.length === arr.length){
                        resolve(list)
                    }
             }, err => {
                reject(err)
            })
        })
    })
}

测试一下

Promise.all([
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(100)
        }, 1000)
    }),
    new Promise((resolve, reject) => {
        resolve(1000)
    })
]).then(data => {
    console.log(data) //返回[100, 1000]
})

Promise.race

Promise.race参数中有一个promise改变状态了,这率先返回结果

Promise.race = function(arr){
    return new Promise((resolve, reject) => {
        arr.forEach((item, index ) => {
            item.then(data => {
                    resolve(data)
                }, err => {
                reject(err)
            })
        })
    })
}

测试一下

Promise.race([
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(100)
        }, 1000)
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1000)
        }, 2000)
    })
]).then(data => {
    console.log(data)/返回100
})

Promise.resolve

Promise.resolve = function(value){
	return new Promise((resolve,reject) => {
    	resolve(value)
	})
}

Promise.reject

Promise.resolve = function(value){
	return new Promise((resolve,reject) => {
    	reject(value)
	})
}