手写Promise

2020-03-20  本文已影响0人  疯狂吸猫

参考:Promise实现原理(附源码)

promise的注意点:

Promise特点

1.状态不可变

2.值穿透,then的回调resolve要是不是一个function而是基本类型,那么这个基本类型就会传递给下一个then 关于promise的一道面试题

3.then的回调resolvethrow erro会跳到下一个then回调的reject

高阶函数:接收函数作为参数的函数

高阶函数——廖雪峰

1.一个最简单的高阶函数:

function add(x, y, f) {//add为高阶函数
    return f(x) + f(y);
}

2.高阶函数决定了回调的调用时间以及接收的参数

例如:高阶函数fn接收函数callBack作为参数,就决定了callBack的调用时间以及callBack的参数

调用fn时定义callBack

function fn(callBack) {//定义一个有回调的function——》fn
    //fn决定何时调用这个回调,以及对回调的传参
    callBack(1,2)
}

fn(function (fir,sec) {//调用fn传入回调,决定回调拿到传参的具体执行
    return fir+sec
})

3.高阶函数的回调接收的参数仍然是函数

例如:

定义高阶函数fn,并且给fn的回调传入函数

调用fn时决定回调的具体内容,以及何时使用fn给的函数参数resolve、reject

function fn(callBack) {//定义一个有回调的function——》fn
    //fn决定何时调用这个回调,以及对回调的传参
    let resolve=function(){
        console.log('resolve')
    }
    let reject=function(){
        console.log('reject')
    }
    
    callBack(resolve,reject)//对回调callBack的传参为函数
    
}

fn(function (resolve,reject) {//调用fn传入回调,决定回调拿到传参的具体执行
    return resolve()//回调的定义中决定什么时候使用收到的传参
})

Promise架构:

1.new Promise().then()

高阶函数的使用:

new MyPromise(handle)的回调——>handles收到的参数为函数

new MyPromise会执行calss MyPromise的构造函数,所以class MyPromise是在定义高阶函数,并且回调接收到的参数也就是函数(resolve、reject)。

class MyPromise{//定义
    constructor(handle){
        handle(this.res,this.rej)
    }
    res(){}

    rej(){}
}
new MyPromise(function (resolve,reject) {//使用
    resolve(1)
}).then()

new MyPromise().then()表示执行MyPromise的构造函数之后立马执行then()

then根据MyPromise实例使用的是resolve()还是reject()来选择回调

所以resolve(),reject改变MyPromise中的this.state,then再根据this.state选择执行resolve还是reject

此步骤完成代码如下:

const PENDING = 'PENDING'//进行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失败

class MyPromise{
    constructor(handle){
        this._value = null
        this._status = PENDING
        handle(this._resolve.bind(this),this._reject.bind(this))
    }
    _resolve(val){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》FULFILLED,不能从别的状态到FULFILLED
        this._value=val
        this._status=FULFILLED
    }

    _reject(val){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》REJECTED,不能从别的状态到REJECTED
        this._value= val
        this._status=REJECTED
    }
}

MyPromise.prototype.then=function (onFulfilled,onRejected) {
    switch (this._status) {
        case PENDING:break;
        case FULFILLED:onFulfilled(this._value);break;
        case REJECTED:onRejected(this._value);break;
    }

}

new MyPromise(function (resolve,reject) {
    resolve('call resolve')
}).then(function (val) {
    console.log(val)
})//call resolve

new MyPromise(function (resolve,reject) {
    reject('call reject')
}).then(function () {},function (val) {
    console.log(val)
})//call reject

注意:1. 高阶函数对this的处理:handle(this._resolve.bind(this),this._reject.bind(this)) 传递_resolve_rejecthandle调用,那么它们的this会随着hangle走,所以此处应该要bind

2.Promise的状态不可变:由于只有_resolve_reject会修改状态,所以只要保证_resolve

_reject修改状态前状态都为PENDING就可以做到状态不可变

2.异步操作

new MyPromise(handle1).then(handle1)是同步的,handle1执行之后会立刻执行then(),异步操作到任务队列中等待执行。但此时handle1的异步操作还没有执行,没有进行resolvereject所以then中的回调也无法执行。

​ 此时引入Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)状态,resolve()可以将Pending转变为Fulfilled,同理reject()Pending转变为Rejected状态

new MyPromise(handle1).then(handle1)执行到then()时如果有异步操作,那么状态仍为Peding,此时将then的回调都储存起来,等待resolve()、reject()执行时再执行。

此步骤完成代码如下:

const PENDING = 'PENDING'//进行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失败

class MyPromise{
    constructor(handle){
        this._value = null
        this._status = PENDING
        // 添加成功回调函数队列
        this._fulfilledQueues = []
        // 添加失败回调函数队列
        this._rejectedQueues = []
        handle(this._resolve.bind(this),this._reject.bind(this))
    }
    _resolve(val){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》FULFILLED,不能从别的状态到FULFILLED
        this._value=val
        this._status=FULFILLED
        let cb
        while (cb=this._fulfilledQueues.shift()){//依次执行成功队列中的函数,并清空队列
            cb(val)
        }
    }

    _reject(val){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》REJECTED,不能从别的状态到REJECTED
        this._value= val
        this._status=REJECTED
        let cb
        while (cb=this._rejectedQueues.shift()){//依次执行失败队列中的函数,并清空队列
            cb(val)
        }
    }
}

//使用例子
MyPromise.prototype.then=function (onFulfilled,onRejected) {
    switch (this._status) {
        case PENDING: this._fulfilledQueues.push(onFulfilled)//待选择,待执行的回头添加到队列
                      this._rejectedQueues.push(onRejected)
                      break
        case FULFILLED: onFulfilled(this._value);break;
        case REJECTED: onRejected(this._value);break;
    }

}

new MyPromise(function (resolve,reject) {
    setTimeout(function () {
        resolve('call resolve')
    },1000)

}).then(function (val) {
    console.log(val)
})//1秒之后输出 call resolve

new MyPromise(function (resolve,reject) {
    setTimeout(function () {
        reject('call reject')
    },2000)

}).then(function () {},function (val) {
    console.log(val)
})//2秒之后输出 call reject

3.链式调用

3.1链式

​ 定义then方法时:

​ 让then返回一个MyPromise对象可实现链式调用。

onFullfilled(val)onRejectedNext(val)的调用决定了new MyPromise().then().then(res,rej)中的第二个then的回调什么时候调用,收到的传参是多少。

MyPromise.prototype.then(function(onFullfilled,onRejected){
    return new MyPromise(function(onFullfilledNext,onRejectedNext){
        onFullfilledNext(val)//onRejectedNext(val)
    })
})

3.2链式与异步

常见情况下,onFullfilledNext的调用时间取决于onFullfilled的调用时间,onFullfilledNext(val)传递的参数valonFullfilled的返回值

但是在异步情况下,onFullfilled是传入._fulfilledQueues队列中等待执行的,所以将onFullfilled打包在fulfilled中延迟调用,将fulfilled代替onFullfilled放入队列。fulfilledonFullfilledNext根据onFullfilled的返回值传参。

此步骤代码:

function isFunction(fn) {
    return typeof fn === 'function'
}
const PENDING = 'PENDING'//进行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失败

class MyPromise{
    constructor(handle){
        this._value = null
        this._status = PENDING
        // 添加成功回调函数队列
        this._fulfilledQueues = []
        // 添加失败回调函数队列
        this._rejectedQueues = []
        try{
            handle(this._resolve.bind(this),this._reject.bind(this))
        }catch (err) {
            this._reject(err)
        }

    }
    _resolve(val){

        const run=() => {
            if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》FULFILLED,不能从别的状态到FULFILLED
            // 依次执行成功队列中的函数,并清空队列
            const runFulfilled = (value) => {
                let cb;
                while (cb = this._fulfilledQueues.shift()) {
                    cb(value)
                }
            }

            // 依次执行失败队列中的函数,并清空队列
            const runRejected = (error) => {
                let cb;
                while (cb = this._rejectedQueues.shift()) {
                    cb(error)
                }
            }

            if(val instanceof MyPromise){
                val.then((value)=>{
                    this._value=value
                    this._status=FULFILLED
                    runFulfilled(value)
                },(err)=>{
                    this._value=err
                    this._status=REJECTED
                    runRejected(err)
                })
            }else {
                this._value=val
                this._status=FULFILLED
                runFulfilled(val)
            }
        }
        setTimeout(run,0)

    }

    _reject(err){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》REJECTED,不能从别的状态到REJECTED

        this._value= err
        this._status=REJECTED
        let cb
        while (cb=this._rejectedQueues.shift()){//依次执行失败队列中的函数,并清空队列
            cb(err)
        }
    }
}

MyPromise.prototype.then=function (onFulfilled,onRejected) {
    return new MyPromise( (onFulfilledNext,onRejectedNext) => {
        let fulfilled=(value) => {
            try {
                let result = onFulfilled(value)
                    onFulfilledNext(result)
            }catch (err) {
                onRejectedNext(err)
            }
        }

        let rejected=(value) => {
            try{
                let result =onRejected(value)
                    onRejectedNext(result)
            }catch (err) {
                onRejectedNext(err)
            }
        }

        switch(this._status){
            case PENDING : this._fulfilledQueues.push(fulfilled)
                this._rejectedQueues.push(rejected)
                break
            case FULFILLED :fulfilled(this._value)
                break
            case REJECTED : rejected(this._value)
                break
        }
    })

}

//使用例子
new MyPromise(function (resolve,reject) {
    setTimeout(function () {
        resolve(new MyPromise(function (resolve) {
            resolve('promise in resolve')
        }))
    },1000)

}).then(function (val) {
    console.log('first then,get message :'+val)//1秒之后输出 first then,get message :promise in resolve
    return 'val form 1st then to 2nd then'
}).then(function (val) {
    console.log('second then,get message:'+val)//1秒之后输出 second then,get message:val form 1st then to 2nd then
})

3.3值穿透与then的回调返回MyPromise对象

1.onFullfilled——》对应调用onFullfilledNext

onFullfilled也就是第一个thenres回调

onFullfilled不为function时:值穿透,直接onFullfilledNext(onFullFiled)

onFullfilled为function时:1.如果返回值不为Promise,onFullfilledNext(返回值)

​ 2.如果返回值为Promise时,返回值.then(onFullfilled)。将onFullfilledNext传给then当回调,由Promise决定何时将执行权传递给then

2.onRejected——》对应调用onRejectedNext

onRejected也就是then的rej回调

onRejected不为function时:值穿透,直接调用onRejectedNext(onRejected)

onRejectedfunction时:1.返回值不为Promise,调用onRejectedNext(返回值)

​ 2.返回值为Promise,调用返回值.then(onRejectedNext)

JS错误处理机制

4.new Promise中resolve传递的值为Promise的实例

resolve(new Promise)

第一个Promise中状态取决于resolve中的Promise

也就是说resolve中的Promise的then回调执行时就能确定第一个Promise的状态

例如下面这种使用形式:

new Promise(function (resolve,reject) {
   return resolve(new Promise(function () {
       
   }))
}).then(function () {

},function () {

})

所以在实现MyPromise中的_resolve时,如果_resolve(val)中的值为Promise的实例,instanceof val=== MyPromise 那么在val.then()的两个回调中改变MyPromise的状态

代码

function isFunction(fn) {
    return typeof fn === 'function'
}
const PENDING = 'PENDING'//进行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失败

class MyPromise{
    constructor(handle){
        this._value = null
        this._status = PENDING
        // 添加成功回调函数队列
        this._fulfilledQueues = []
        // 添加失败回调函数队列
        this._rejectedQueues = []
        try{
            handle(this._resolve.bind(this),this._reject.bind(this))
        }catch (err) {
            this._reject(err)
        }

    }
    _resolve(val){

        const run=() => {
            if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》FULFILLED,不能从别的状态到FULFILLED
            // 依次执行成功队列中的函数,并清空队列
            const runFulfilled = (value) => {
                let cb;
                while (cb = this._fulfilledQueues.shift()) {
                    cb(value)
                }
            }

            // 依次执行失败队列中的函数,并清空队列
            const runRejected = (error) => {
                let cb;
                while (cb = this._rejectedQueues.shift()) {
                    cb(error)
                }
            }

            if(val instanceof MyPromise){
                val.then((value)=>{
                    this._value=value
                    this._status=FULFILLED
                    runFulfilled(value)
                },(err)=>{
                    this._value=err
                    this._status=REJECTED
                    runRejected(err)
                })
            }else {
                this._value=val
                this._status=FULFILLED
                runFulfilled(val)
            }
        }
        setTimeout(run,0)

    }

    _reject(err){
        if (this._status !== PENDING) return//状态不可逆,只能从PENDING——》REJECTED,不能从别的状态到REJECTED

        this._value= err
        this._status=REJECTED
        let cb
        while (cb=this._rejectedQueues.shift()){//依次执行失败队列中的函数,并清空队列
            cb(err)
        }
    }
}

MyPromise.prototype.then=function (onFulfilled,onRejected) {
    return new MyPromise( (onFulfilledNext,onRejectedNext) => {
        let fulfilled=(value) => {
            if(!isFunction(onFulfilled)) {
                onFulfilledNext(value) //值穿透
                return
            }

            try {
                let result = onFulfilled(value)
                if(result instanceof MyPromise){
                    result.then(onFulfilledNext,onRejectedNext)
                }else {
                    onFulfilledNext(result)
                }
            }catch (err) {
                onRejectedNext(err)
            }
        }

        let rejected=(value) => {
            if(!isFunction(onFulfilled)) {
                onRejectedNext(value)
                return
            }
            try{
                let result =onRejected(value)
                if(result instanceof  MyPromise){
                    result.then(onFulfilledNext,onRejectedNext)
                } else {
                    onRejectedNext(result)
                }
            }catch (err) {
                onRejectedNext(err)
            }
        }
        switch(this._status){
            case PENDING : this._fulfilledQueues.push(fulfilled)
                           this._rejectedQueues.push(rejected)
                           break
            case FULFILLED :fulfilled(this._value)
                            break
            case REJECTED : rejected(this._value)
                            break
        }
    })
}

//使用例子
new MyPromise(function (resolve,reject) {
    setTimeout(function () {
        resolve(new MyPromise(function (resolve) {
            resolve('promise in resolve')
        }))
    },1000)

}).then(function (val) {
    console.log('first then,get message :'+val)//1秒之后输出 first then,get message :promise in resolve
    return new MyPromise(function (resolve) {
        setTimeout(()=>{
            return resolve('promise in then')
        },1000)

    })
}).then(function (val) {
    console.log('second then ,get message:'+val)//2秒之后输出 second then ,get message:promise in then
})

上一篇下一篇

猜你喜欢

热点阅读