手写Promise

参考: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
})

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,362评论 6 537
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,013评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 177,346评论 0 382
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,421评论 1 316
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,146评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,534评论 1 325
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,585评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,767评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,318评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,074评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,258评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,828评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,486评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,916评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,156评论 1 290
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,993评论 3 395
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,234评论 2 375