资讯专栏INFORMATION COLUMN

从零实现一个简单的 Promise

kviccn / 3313人阅读

摘要:本文参考了实践教程实现这个视频,并添加了自己的一些想法。三种状态必须是函数初始状态是返回值完成时调用的方法,这里做了容错拒绝时调用的方法再次运行,正确打印出结果。

本文参考了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://www.ucloud.cn/yun/84458.html

相关文章

  • 从零实现一个简易 Promise

    从零实现一个简易的 Promise 所有问题都可以通过加一层中间层来解决。 Promises/A+ 简易的,不做废话直接开始 :) const p = new Promise((resolve, reject)=>{ // 如果操作成功则调用 resolve 并传入 value // 如果操作失败则调用 reject 并传入 reason }); 通常我们都会使用上述方法获取 P...

    WilsonLiu95 评论0 收藏0
  • 从零开始实现一个自己Promise

    摘要:所以,这篇文章我会带大家从零开始,手写一个基本能用的。首先,规定对象是一个构造函数,用来生成实例。然后,这个构造函数接受一个函数作为参数,该函数的两个参数分别是和。对象通过自身的状态,来控制异步操作。 刚开始写前端的时候,处理异步请求经常用callback,简单又顺手。后来写着写着就抛弃了callback,开始用promise来处理异步问题。promise写起来确实更加优美,但由于缺乏...

    paulquei 评论0 收藏0
  • 从零开始写一个 Promise

    摘要:是什么在规范中,是一个类,它的构造函数接受一个函数。在这种情况下,是但处于状态。与一起使用关键字会暂停执行一个函数,直到等待的变成状态。此外,会一直等待调用直到下一个时序。 原文:Write Your Own Node.js Promise Library from Scratch作者:code_barbarian Promise 已经是 JavaScript 中异步处理的基石,回调...

    Binguner 评论0 收藏0
  • 前端之从零开始系列

    摘要:只有动手,你才能真的理解作者的构思的巧妙只有动手,你才能真正掌握一门技术持续更新中项目地址求求求源码系列跟一起学如何写函数库中高级前端面试手写代码无敌秘籍如何用不到行代码写一款属于自己的类库原理讲解实现一个对象遵循规范实战手摸手,带你用撸 Do it yourself!!! 只有动手,你才能真的理解作者的构思的巧妙 只有动手,你才能真正掌握一门技术 持续更新中…… 项目地址 https...

    Youngdze 评论0 收藏0
  • 从零开始搭建React同构应用(四):搭建Koa Server & 完善SSR

    摘要:从零开始搭建同构应用四搭建完善上一篇我们使用了的方式测试了,这篇文章来讲如何在前文的基础上搭建一个,实现真正意义上的。至此,一个简单的框架已经搭建完成,剩下的工作就是结合工作需要,在里面添砖加瓦啦。 从零开始搭建React同构应用(四):搭建Koa Server & 完善SSR 上一篇我们使用了CLI的方式测试了SSR,这篇文章来讲如何在前文的基础上搭建一个Koa Server,实现真...

    fizz 评论0 收藏0

发表评论

0条评论

kviccn

|高级讲师

TA的文章

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