资讯专栏INFORMATION COLUMN

手写一个符合promise/A+规范的promise库

venmos / 2932人阅读

摘要:使用及原理分析通过关键字创建实例接受一个参数方法返回两个方法可用通过在方法中通过调用使成功或调用使失败来控制状态中可以执行同步代码也可以执行异步代码原型对象上有方法供实例调用方法接受两个参数默认为一个函数默认为一个函数当状态为时执行用户传入

promise使用及原理分析:

通过new关键字创建promise实例, 接受一个executor参数, executor方法返回两个方法 resolve, reject, 可用通过在executor方法中通过调用resolve(使成功)或调用reject(使失败),来控制promise状态

let p = new Promise((resolve, reject) => {
    resolve(100)
})

executor中可以执行同步代码也可以执行异步代码

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(100)
    })
})

promise原型对象上有then方法供promise实例调用, then方法接受两个参数onFulfilled, onRejected

onFulfilled默认为一个函数 data => data

onRejected默认为一个函数 err => {throw err}

当promise状态为fulfilled时, 执行用户传入的onFulfilled方法

当promise状态为rejected时, 执行用户传入的onRected方法

当用户创建promise对象时采用异步,那么执行then方法时没有调用resolve方法或reject方法,所以promise状态依然为pending状态,所以需要在then方法中采取发布订阅模式,先保存then方法传来的onFulfilled和onReje

又因为同一个promise实例可以调用多次then方法,从而传多个onFulfilled和onRected,所以发布订阅采用数组保存

onFulfilled和onRejected方法中可能throw Error, 所以在执行onFulfilled和onRejected时需要try catch捕获

then方法返回一个新的Promise实现链式编程

统一判断then方法传入的onFulfilled方法和onRejected方法中return的类型(resolvePromise)

p.then(data => {
    console.log(data)
}, err => {
    console.log(err)
})
let p1 = p.then(data => {
    return p1   // 报类型错误
})
p.then(data => {
    return new Promise((resolve, reject) => {
        resolve(100)
    })
})

catch方法接受一个错误回调,可以用then方法实现(语法糖)

ES2018 中新增finally方法 也可以通过then方法实现(语法糖) finally要实现值得穿透, finally前如果有then方法,其返回值要穿过finally方法传给之后的then

p.then(data => {
    return 100
}).finally(() => {
    console.log("finally")
}).then(data => {
    console.log(data)  // 100
})

all, race 方法都接受一个promise数组

all方法要所有promise都返回才resolve一个全部是成功态的数组,只要有一个rejected就直接reject

race方法只要有一个promise resolve就直接resolve

完整代码如下:
class Promise {
    constructor(executor) {
        this.status = Promise.PENDING
        this.value = undefined
        this.reason = undefined
        // 发布订阅的存储器onResolvedCallbacks, onRejectedCallbacks
        this.onResolvedCallbacks = []
        this.onRejectedCallbacks = []
        this.initBind()
        this.init(executor)
    }
    initBind() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }
    init(executor) {
        // 防止executor中抛错
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    resolve(data) {
        // 如果resolve中传入一个promise, 那么返回改promise结果
        if (data instanceof Promise) data.then(this.resolve, this.reject)
        if (this.status === Promise.PENDING) {
            this.status = Promise.FULFILLED
            this.value = data
            this.onResolvedCallbacks.forEach(fn => fn())
        }
    }
    reject(reason) {
        if (this.status === Promise.PENDING) {
            this.status = Promise.REJECTED
            this.reason = reason
            this.onRejectedCallbacks.forEach(fn => fn())
        }
    }
    then(onFulfilled, onRejected) {
        const fulfilledHandle = (resolve, reject) => {
            // 此处用setTimeout异步才能拿到promise2
            setTimeout(() => {
                try {
                    let x = onFulfilled(this.value)
                    Promise.resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }
        const rejectHandle = (resolve, reject) => {
            setTimeout(() => {
                try {
                    let x = onRejected(this.reason)
                    Promise.resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }
        // onFulfilled和onRejected定义默认值
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
        onRejected = typeof onRejected === "function" ? onRejected : reason => {
            throw reason
        }
        let promise2 = new Promise((resolve, reject) => {
            if (this.status === Promise.FULFILLED) {
                fulfilledHandle(resolve, reject)
            }
            if (this.status === Promise.REJECTED) {
                rejectHandle(resolve, reject)
            }
            if (this.status === Promise.PENDING) {
                this.onResolvedCallbacks.push(() => {
                    fulfilledHandle(resolve, reject)
                })
                this.onRejectedCallbacks.push(() => {
                    rejectHandle(resolve, reject)
                })
            }
        })
        // 返回一个新的promise
        return promise2
    }
    catch (onRejected) {
        return this.then(null, onRejected)
    }
    static resolve() {
        return new Promise((resolve, reject) => {
            resolve()
        })
    }
    static reject() {
        return new Promise((resolve, reject) => {
            reject()
        })
    }
    finally(callback) {
        return this.then(
            data => Promise.resolve(callback()).then(() => data),
            err => Promise.resolve(callback()).then(() => {
                throw err
            })
        )
    }
    static all(promises) {
        return new Promise((resolve, reject) => {
            let result = []
            let count = 0
            const setResult = (key, value) => {
                result[key] = value
                if (++count === promises.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < promises.length; i++) {
                let current = promises[i]
                if (Promise.isPromise(current)) {
                    current.then(data => {
                        setResult(i, data)
                    }, reject)
                } else {
                    setResult(i, current)
                }
            }
        })
    }
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                let current = promises[i]
                if (Promise.isPromise(current)) {
                    current.then(resolve, reject)
                } else {
                    resolve(current)
                }
            }
        })
    }
}
Promise.PENDING = "pending"
Promise.FULFILLED = "fulfilled"
Promise.REJECTED = "rejected"
Promise.resolvePromise = (promise2, x, resolve, reject) => {
    // called防止他人的promise即执行resolve又执行 reject
    let called
    if (promise2 === x) throw new TypeError("xxx")
    if (typeof x === "function" || typeof x === "object" && x !== null) {
        try {
            let then = x.then
            if (typeof then === "function") {
                then.call(x, y => {
                    if (called) return
                    called = true
                    // 递归解析,总有一个结果then方法返回一个普通值
                    Promise.resolvePromise(promise2, y, resolve, reject)
                }, e => {
                    if (called) return
                    called = true
                    reject(e)
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true
            reject(e)
        }
    } else {
        resolve(x)
    }
}
Promise.isPromise = (obj) => {
    return typeof obj === "function" || typeof obj === "object" && obj !== null && obj.then && typeof obj.then === "function"
}
// 延迟对象
Promise.deferred = () => {
    const defer = {}
    defer.promise = new Promise((resolve, reject) => {
        defer.resolve = resolve
        defer.reject = reject
    })
    return defer
}

module.exports = Promise

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104774.html

相关文章

  • 手写一个符合A+规范Promise

    摘要:本文同时也发布在我的博客上,欢迎之前也手写过简单的,这次则是为了通过官方的测试集,借鉴了一些下载量较多的,改了几遍,终于是通过了规范的个测试用例如何测试测试库地址在这,大家在写完自己的后,不妨也去测试一下,检验自己的是否符合规范。 本文同时也发布在我的github博客上,欢迎star~ 之前也手写过简单的promise,这次则是为了通过官方的Promise A+测试集,借鉴了一些下载量...

    jsummer 评论0 收藏0
  • 手写一款符合Promise/A+规范Promise

    摘要:手写一款符合规范的长篇预警有点长,可以选择性观看。初始状态是,状态可以有或者不能从转换为或者从转换成即只要由状态转换为其他状态后,状态就不可变更。 手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看。如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不...

    rubyshen 评论0 收藏0
  • 一步一步实现一个符合PromiseA+规范Promise(1)

    摘要:今天我们来自己手写一个符合规范的库。是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大。我们可以看到,其实就是一个构造函数。所以说我们的数组里存的是一个一个的的回调函数,也就是一个一个。 今天我们来自己手写一个符合PromiseA+规范的Promise库。大家是不是很激动呢?? showImg(https://segmentfault.com/img/bV6t4Z?...

    joyvw 评论0 收藏0
  • promise/A+规范翻译以及手写实现

    摘要:如果实现满足所有要求,则实现可能允许。本条款允许使用特定于实现的方法来采用已知一致承诺的状态。接下来根据规范进行手写实现注释偷懒就将对应的规范标注出来,其实基本上就是对着规范实现。 如果要手写实现promise,那么先看看promise/A+规范,再来实现,将会事半功倍。那么我先翻译一下Promise/A+规范中的内容。 术语 1.1 promise 是一个带有符合此规范的the...

    LiuZh 评论0 收藏0
  • 异步发展流程 —— 手写一个符合 Promise/A+ 规范 Promise

    摘要:构造函数的实现我们在使用的时候其实是使用关键字创建了一个的实例,其实是一个类,即构造函数,下面来实现构造函数。 showImg(https://segmentfault.com/img/remote/1460000018998456); 阅读原文 概述 Promise 是 js 异步编程的一种解决方案,避免了 回调地狱 给编程带来的麻烦,在 ES6 中成为了标准,这篇文章重点不是叙...

    UnixAgain 评论0 收藏0

发表评论

0条评论

venmos

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<