抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

前两天翻出以前写的各种手写原生代码,发现快忘干净了,最近准备重新捡起来

初步构建

简单实现一下”表面“上的Promise:

  • 三个状态:pending,fulfilled,rejected

  • 构造函数传入回调函数,回调函数传入两个函数,回调函数里可以调用类里的resolve,reject

  • resolve、reject的时候会改变内部状态,resolve传来的值会改变内部的value

class Promise {
    static PENDING = 'pending'
    static FULFILLED = 'fulfilled'
    static REJECTED = 'rejected'

    constructor(executer) {
        this.status = Promise.PENDING
        this.value = undefined
        executer(this.resolve, this.reject)
    }
	resolve(result) {
        this.value = result
        this.status = Promise.FULFILLED
    }

    reject(reason) {
        this.value = reason
        this.status = Promise.REJECTED
    }
}

const p = new Promise((resolve,reject)=>{
    console.log(1)
    resolve(1)
})
console.log(p)
/*ouput:

1
file:///D:/MYSOURSE/project/nodejs/promise.js:10
    resolve() {this.status = Promise.FULFILLED}
                           ^

TypeError: Cannot set property 'status' of undefined
    at resolve (file:///D:/MYSOURSE/project/nodejs/promise.js:10:28)
    at file:///D:/MYSOURSE/project/nodejs/promise.js:16:5
    at new Promise (file:///D:/MYSOURSE/project/nodejs/promise.js:8:9)
    at file:///D:/MYSOURSE/project/nodejs/promise.js:14:11
    at ModuleJob.run (internal/modules/esm/module_job.js:146:23)
    at async Loader.import (internal/modules/esm/loader.js:165:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)

*/

报错了,写的很明白,status是个undefined,也就是this对象上没有这个东西,所以this是谁呢,简单分析一下:constructor接收一个回调函数,回调函数里传入类里的resolve,当回调函数执行的时候会调用参数里的resolve方法,这个是在executer里调用的,谁调用的this就指向谁,executer的this是window,resolve也是window调用的,但是在类里默认开启了严格模式,所以this指向undefined

解决方法:bind绑定this

class Promise {
    static PENDING = 'pending'
    static FULFILLED = 'fulfilled'
    static REJECTED = 'rejected'

    constructor(executer) {
        this.status = Promise.PENDING
        executer(this.resolve.bind(this), this.reject.bind(this))
    }
    resolve(result) {
        this.value = result
        this.status = Promise.FULFILLED
    }

    reject(reason) {
        this.value = reason
        this.status = Promise.REJECTED
    }
}

const p = new Promise((resolve,reject)=>{
    console.log(1)
    resolve(1)
})
console.log(p)
/*
output:

1
Promise { status: 'fulfilled' }

*/

继续照着原始的Promise开始模仿

完善resolve、reject方法:

根据PromiseA+规范:

一个Promise必须处在其中之一的状态:pending, fulfilled 或 rejected.

  • 如果是pending状态,则promise:
    • 可以转换到fulfilled或rejected状态。
  • 如果是fulfilled状态,则promise:
    • 不能转换成任何其它状态。
    • 必须有一个值,且这个值不能被改变。
  • 如果是rejected状态,则promise可以:
    • 不能转换成任何其它状态。
    • 必须有一个原因,且这个值不能被改变。

所以在改变状态的时候加个判断,只有状态是pending的时候才能改变:

resolve(result) {
    if (this.status === Promise.PENDING) {
        this.value = result
        this.status = Promise.FULFILLED
    }
}
reject(reason) {
    if (this.status === Promise.PENDING) {
        this.value = reason
        this.status = Promise.REJECTED
    }
}

then方法

then方法接受两个函数,一个是resolve时调用的,一个是reject时调用的,只要then方法传来了参数,把他暂存一下,当状态改变的时候再调用对应的方法就好了

constructor里声明一个成功和失败的回调函数:

constructor(executer) {
    this.status = Promise.PENDING
    this.value = undefined
    this.successCallback = () => {
    }
    this.failCallback = () => {
    }
    executer(this.resolve.bind(this), this.reject.bind(this))
}

then方法:

then(onFulfilled, onRejected) {
    // 没有传函数的时候默认给个什么都不干的函数
    if (typeof onFulfilled !== 'function') {
        onFulfilled = () => {
        }
    }
    if (typeof onRejected !== 'function') {
        onRejected = () => {
        }
    }
    // 当前状态是pending的时候,说明有任务还没有resolve,这时候暂存一下
    if (this.status === Promise.PENDING) {
        this.successCallback = () => {
            onFulfilled(this.value)
        }

        this.failCallback = () => {
            onRejected(this.value)
        }
    }
    // 执行到then的时候前面的状态已经改变了,说明走的是同步代码,直接执行就好了
    if (this.status === Promise.FULFILLED) {
        onFulfilled(this.value)
    }
    if (this.status === Promise.REJECTED) {
        onRejected(this.value)
    }
}

resolve方法:

resolve(result) {
    if (this.status === Promise.PENDING) {
        this.value = result
        this.status = Promise.FULFILLED
        // 执行到这里的时候任务已经resolve了,调用callback
        this.successCallback()
    }
}

测试:

const p = new Promise((resolve, reject) => {
    console.log(1)
    resolve(22)
}).then(res => {
    console.log(res)
})
console.log(p)
/*
output:

1
22
undefined

*/


现在其实有点问题:

  • 首先打印的顺序问题,Promise的异步任务应该晚于打印p执行;
  • 打印的p是undefined说明then没有返回值,没有实现链式调用;
  • 回调函数每个状态就那么一个函数,如果多个任务肯定是不够用,虽然现在then还不能链式调用,且听下回分解

手写Promise(二) - 孙泽辉 (foggy.shop)

评论