从零实现一个简单的 Promise

本文参考了Node.js 实践教程 - Promise 实现这个视频,并添加了本身的一些想法。javascript

首先来看 Promise 的构造:html

// 这里用 Prometheus 代替 Promise
let p = new Prometheus((resolve, reject) => {
    resolve('hello')
})

下面咱们来实现它:java

// 三种状态
const PENDING = Symbol()
const FULFILLED = Symbol()
const REJECTED = Symbol()

function Prometheus (fn) {
    // fn 必须是函数
    if (typeof fn !== 'function') {
        throw new Error('fn must be a function!')
    }

    let state = PENDING // 初始状态是 PENDING
    let value = null // 返回值

    function fulfill (result) {
        state = FULFILLED
        value = result
    }

    // 完成时调用的方法,这里作了容错
    function resolve (result) {
        try {
            fulfill(result)
        } catch (err) {
            reject(err)
        }
    }

    // 拒绝时调用的方法
    function reject (error) {
        state = REJECTED
        value = error
    }

    fn(resolve, reject)
}

第二步,实现 then 方法:promise

let p = new Prometheus((resolve, reject) => {
    resolve('hello')
})

p.then(val => {
    console.log(val)
})
// 三种状态
const PENDING = Symbol()
const FULFILLED = Symbol()
const REJECTED = Symbol()

function Prometheus (fn) {
    // fn 必须是函数
    if (typeof fn !== 'function') {
        throw new Error('fn must be a function!')
    }

    let state = PENDING // 初始状态是 PENDING
    let value = null // 返回值

    function fulfill (result) {
        state = FULFILLED
        value = result
    }

    // 完成时调用的方法,这里作了容错
    function resolve (result) {
        try {
            fulfill(result)
        } catch (err) {
            reject(err)
        }
    }

    // 拒绝时调用的方法
    function reject (error) {
        state = REJECTED
        value = error
    }

    this.then = function (onFulfill, onReject) {
        switch (state) {
            case FULFILLED:
                onFulfill(value)
                break
            case REJECTED:
                onReject(value)
                break
        }
    }

    fn(resolve, reject)
}

第三步,在 Promise 里使用异步bash

let p = new Prometheus((resolve, reject) => {
    setTimeout(() => {
        resolve('hello')
    }, 0)
})

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

直接运行上面的代码发现控制台没有打印出 hello,缘由是 Prometheus 里的代码是异步执行,致使记下来执行 then 方法的时候,statePENDING,后面再执行 resolve 的时候就不会走到 onFulfill 了,因此咱们要在 then 方法里添加 statePENDING 的分支判断,把 onFulfillonReject 存到一个变量中:异步

// 三种状态
const PENDING = Symbol()
const FULFILLED = Symbol()
const REJECTED = Symbol()

function Prometheus (fn) {
    // fn 必须是函数
    if (typeof fn !== 'function') {
        throw new Error('fn must be a function!')
    }

    let state = PENDING // 初始状态是 PENDING
    let value = null // 返回值
    let hanler = {}

    function fulfill (result) {
        state = FULFILLED
        value = result
        handler.onFulfill(result)
    }

    // 完成时调用的方法,这里作了容错
    function resolve (result) {
        try {
            fulfill(result)
        } catch (err) {
            reject(err)
        }
    }

    // 拒绝时调用的方法
    function reject (error) {
        state = REJECTED
        value = error
        handler.onReject(error)
    }

    this.then = function (onFulfill, onReject) {
        switch (state) {
            case FULFILLED:
                onFulfill(value)
                break
            case REJECTED:
                onReject(value)
                break
            case PENDING:
                handler = { onFulfill, onReject }
        }
    }

    fn(resolve, reject)
}

异步实现了,咱们再回过头看看同步是否正常运行:函数

let p = new Prometheus((resolve, reject) => {
  resolve('hello')
})

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

发现报错信息:this

TypeError: handler.onReject is not a function

由于同步执行的时候,fulfillhandler{},因此会报错。code

// 三种状态
const PENDING = Symbol()
const FULFILLED = Symbol()
const REJECTED = Symbol()

function Prometheus (fn) {
    // fn 必须是函数
    if (typeof fn !== 'function') {
        throw new Error('fn must be a function!')
    }

    let state = PENDING // 初始状态是 PENDING
    let value = null // 返回值
    let handler = {}

    function fulfill (result) {
        state = FULFILLED
        value = result
        next(handler)
    }

    // 完成时调用的方法,这里作了容错
    function resolve (result) {
        try {
            fulfill(result)
        } catch (err) {
            reject(err)
        }
    }

    // 拒绝时调用的方法
    function reject (error) {
        state = REJECTED
        value = error
        next(handler)
    }

    function next({ onFulfill, onReject }) {
        switch (state) {
            case FULFILLED:
                onFulfill && onFulfill(value)
                break
            case REJECTED:
                onReject && onReject(value)
                break
            case PENDING:
                handler = { onFulfill, onReject }
        }
    }

    this.then = function (onFulfill, onReject) {
        next({onFulfill, onReject})
    }

    fn(resolve, reject)
}

如今同步也能够正常运行了,接下来看看多个 then 链式调用:视频

let p = new Prometheus((resolve, reject) => {
  resolve('hello')
})

p.then(val => {
    console.log(val)
    return 'world'
}).then(val => {
    console.log(val)
})

执行代码会发现以下报错信息:

TypeError: Cannot read property 'then' of undefined

缘由是 then 方法没有返回 Promise

// 三种状态
const PENDING = Symbol()
const FULFILLED = Symbol()
const REJECTED = Symbol()

function Prometheus (fn) {
    // fn 必须是函数
    if (typeof fn !== 'function') {
        throw new Error('fn must be a function!')
    }

    let state = PENDING // 初始状态是 PENDING
    let value = null // 返回值
    let handler = {}

    function fulfill (result) {
        state = FULFILLED
        value = result
        next(handler)
    }

    // 完成时调用的方法,这里作了容错
    function resolve (result) {
        try {
            fulfill(result)
        } catch (err) {
            reject(err)
        }
    }

    // 拒绝时调用的方法
    function reject (error) {
        state = REJECTED
        value = error
        next(handler)
    }

    function next({ onFulfill, onReject }) {
        switch (state) {
            case FULFILLED:
                onFulfill && onFulfill(value)
                break
            case REJECTED:
                onReject && onReject(value)
                break
            case PENDING:
                handler = { onFulfill, onReject }
        }
    }

    this.then = function (onFulfill, onReject) {
        return new Prometheus((resolve, reject) => {
            next({
                onFulfill: val => {
                    resolve(onFulfill(val))
                },
                onReject: err => {
                    reject(onReject(err))
                }
            })
        })
    }

    fn(resolve, reject)
}

再次运行,正确打印出结果。

到此,一个很是简单的 Promise 就实现了,固然,这里其实还有不少细节没有考虑,具体还要参考 Promise/A+

相关文章
相关标签/搜索