从零完成一个简朴的 Promise

本文参考了Node.js 实践教程 – Promise 完成这个视频,并增加了本身的一些主意。

起首来看 Promise 的组织:

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

下面我们来完成它:

// 三种状况
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 要领:

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 里运用异步

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)
})

发明报错信息:

TypeError: handler.onReject is not a function

由于同步实行的时刻,fulfillhandler{},所以会报错。

// 三种状况
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+

    原文作者:张宗正
    原文地址: https://segmentfault.com/a/1190000010410543
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞