手写 Promise 系列 --- 1

2019-06-26  本文已影响0人  人话博客

Promise 是 ES6 推出的用于解决callback嵌套层级太深问题的一种异步方案.

基本使用如下.

let myPromise = new Promise((resolve,reject) => {
    setTimeout(()=>{
        resolve("true") // reject("false")
    },1000)
})

myPromise.then(data=>{
    console.log(data)
},err=>{
    console.log(err)
})

先不考虑那么多,也不像很多博客里写的那种,一上来就给非常完美的思路和非常标准的 Promise/A+ 规范.

我就按照自己思路一点点的来做.


step 01 从代码代用级别摸清内部构造

image.png

然后看上述写的代码.

let myPromise = new Promise((resolve,reject) => {
    setTimeout(()=>{
        resolve("true") // reject("false")
    },1000)
})

function MyPromise () {

}

// 肯定是 
let my_promise = new MyPromise()

function MyPromise (func) {
    typeof func === 'function' ===> true
}
function MyPromise((resolve,reject) => {
    typeof reject === 'function'  // true
    typeof resolve === 'function' // true
})
function MyPromise() {
    //xxx    
}

new MyPromise((resolve,reject) => {
    setTimeout(() => {
        reslove(data) // or reject (err)
    },1000)
})

function MyPromise() {
    //xxx    
}

new MyPromise((resolve,reject) => {
    setTimeout(() => {
    // resovle 哪来的?
        reslove(data) // or reject (err) // reject 哪来的?
    },1000)
})

function MyPromise () {
    function resolve () {}
    function reject () {}
}
function MyPromise () {
    function resolve () {
        // pending ---> resolve
    }
    function reject () {
        // pending ---> reject
    }
}

new MyPromise(executor).then(resolveData=>{},rejectData=>{})

step 02 根据上述推理,猜测内部写法.

1. 首先是一个构造函数

function MyPromise () {

}

2. 其次需要接受一个执行器.

function MyPromise (executor) {
    
}

3. 实例化出来的 Promise 对象有三种状态

MyPromise.prototype.states = {
    PENDING: 'PENDING',
    RESOLVE: 'RESOLVE',
    REJECT: 'REJECT'
}

4. 一开始 promise 对象是 pending 状态

function MyPromise (executor) {
    this.state = this.states.PENDING // pending.
}

5. 内部起码得有两个 reject 和 resolve.要不然executor里面的reject 和 resolve 哪来的? 或者把这两个方法

function MyPromise (executor) {
    this.state = this.states.PENDING // pending.
    const that = this // 挂载 this
    function resolve () {
        if (that.state === this.states.PENDING) {
            that.state = this.states.PENDING
        }
    }
    
    function reject () {
        if (that.state === this.states.PENDING) {
            that.state = this.states.REJECT
        }
    }
}

或者觉得挂载 this 麻烦,我就把 resolve 和 reject 挂在 prototype 上.

MyPromise.prototype.reject = function () {
    if (this.state === this.states.PENDING) {
        this.state = this.states.REJECT
    }
}

MyPromise.prototype.resolve = function () {
    if (this.state === this.states.PENDING) {
        this.state = this.states.RESOLVE
    }
}

到目前为止,我们可以通过 executor 内部调用 reject 或者 resolve 修改某个 Promise 的状态了.

在回到我们使用 ES6 的 Promise 代码中.

new Promise ((resolve,reject) => {
    resolve(someData) // or reject(someError)
}) 

可以知道 reslove 和 reject 是可以接受参数的.

6. 给 reject 和 resolve 来设置一个形参

// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.REJECT
    }
}

// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.RESOLVE
    }
}

7.我们通过 then 传递了两个函数,第一个是成功的回调. 第二个是失败的回调.

MyPromise.prototype.then = function (onResolve,onReject) {
    this.onResloveCallback = onResolve
    this.onRejectCallback = onReject
}


在回到 ES6 的 Promise 调用代码中.

let p = new Promise((resolve,reject) => {
    setTimeout(()=>{
        resolve(data形参) // reject(失败形参)
    },1000)
})

p.then(data=>{
    data === data 形参
})

8.resolve的形参传递给了then的第一个回调函数的参数,error传递给了then的第二个回调函数的参数

// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.REJECT
        this.error = error
    }
}

// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.RESOLVE
        this.data = data
    }
}


9. 状态改变完成之后,就需要调用从then函数接受过来的两个函数参数了(reject&resolve)

// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.REJECT // 该状态
        this.error = error // 记录值
        this.onRejectCallback(this.error) // 调用回调
    }
}

// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.RESOLVE // 改状态
        this.data = data // 记录值
        this.onResolveCallback(data) // 调用回调
    }
}

完整的代码

function MyPromise (executor) {
    this.state = this.states.PENDING
    this.value = null // 用于记录executor内部的reject or resolve 传递回来的值.
    this.onRejectCallback = null
    this.onResolveCallback = null
    
    
    executor(this.resolve.bind(this),this.reject.bind(this))

}

MyPromise.prototype.states = {
    PENDING: 'PENDING',
    RESOLVE: 'RESOLVE',
    REJECT: 'REJECT'
}

// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.REJECT // 该状态
        this.error = error // 记录值
        this.onRejectCallback(this.error) // 调用回调
    }
}

// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
    if (this.state === this.states.PENDING) {
        this.state = this.states.RESOLVE // 改状态
        this.data = data // 记录值
        this.onResolveCallback(data) // 调用回调
    }
}



step 03 . 测试MyPromise 的 resolve 和 reject

测试调用自定义的promise ---> pending --> resolve

new MyPromise((resolve, reject) => { 
  setTimeout(() => {
    resolve(1)
  }, 1000);
}).then(data => { console.log(data) }, error => { console.log(error) })

正确输出.

image.png

测试调用自定义的promise ---> pending --> reject

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('error')
  }, 1000);
}).then(data => { console.log(data) }, error => { console.log(error) })

错误输出.

image.png

第一阶段手写 Promise 达成目标:

补充一点:

如果把 reject 和 resolve 写在 prototype 上,然后直接通过 this.reject/resolve 传递会导致 this 指向的错误(obj.method当函数传递,只能传 method, 不会传 obj,真正的纯函数传递).所以,上述代码一定要写成.

executor(this.resolve.bind(this),this.reject.bind(this))
上一篇 下一篇

猜你喜欢

热点阅读