【手撕系列】Promise then的实现(二)

简介: Promise then的实现

a89c757eefc9b385e16f733790547f1.png

then 方法基础功能实现

上一节我们简单实现了 resolve和reject 对结果的处理,但它的结果是直接输出的,我们希望它能够和们熟悉的用法一样,通过then方法来接受处理结果的回调,现在我们来一起实现一个简单的 then 方法

class MyPromise {
    // ...
    then(onFulfilled, onRejected) {
        if (this.state === MyPromise.fulfilled) {
            onFulfilled(this.result)
        }
        if (this.state === MyPromise.rejected) {
            onRejected(this.error)
        }
    }
}
new MyPromise((resolve, reject) => {
    resolve(1)
    reject(2)
}).then(res => {
    console.log(res);
}, error => {
    console.log(error)
})
复制代码

这里,我们通过 onFulfilled,onRejected 接收我们 then 里的回调函数,通过判断 state 状态来决定走哪个分支,这样一个简单的 then 方法就完成了,但它是一个同步的方法,大家知道 then 最大的作用是异步的处理结果,那我们接下来就对 then 做异步的处理

then 方法异步实现

当传进 MyPromise 的回调函数是一个异步方法的时候,我们就无法保证调用 then 时能够拿到我们想要的结果(异步事件还未处理完),那这个时候 Promise 的状体仍旧处于 Pending 状态,那我们这里可以采用发布订阅者模式,在调用 then 方法过程中,如果状态是 pending 的,先把要执行的函数记录下来,后续状态改变时在把记录的方法执行就可以了

在实现代码之前先简单介绍下发布订阅者模式的实现

发布订阅者的实现思路

  • 维护一个缓存列表(事件调度中心)
  • 订阅者把函数 fn 添加到缓存列表中(订阅者注册事件到调度中心)
  • 发布者在事件发生时通知调度中心(发布者发布事件到调度中心,调度中心处理代码)

按照上述思路我们简单梳理下逻辑

  • 事件调度中心

这个场景下,我们需要记录的事件就是 resolve与reject 事件,他们两个是相互独立的,那我们就定义两个数组onResolveCallbacks 和 onRejectCallbacks去作为我们的事件调度中心

// 事件调度中心
this.onResolveCallbacks = []
this.onRejectCallbacks = []
复制代码
  • 订阅者

then 方法则作为订阅者,当执行时如果状态还为 pending 时,把回调方法添加到数组中(事件调度中心)

// 等待状态时暂存回调方法(这里的方法注意用箭头函数包裹起来)
if (this.state === MyPromise.pending) {
    this.onResolveCallbacks.push(() => {
        onFulfilled(this.result)
    })
    this.onRejectCallbacks.push(() => {
        onRejected(this.error)
    })
}
复制代码
  • 发布者

最后当resolve或者reject执行时,作为发布者把事件调度中心注册的事件进行执行

const resolve = (res) => {
    if (this.state === MyPromise.pending) {
        // ...
        // 状态改变发布消息时执行对应调度中心的方法
        this.onResolveCallbacks.forEach(callBack => callBack())
    }
}
复制代码

这样,一个简单的订阅发布者模式就完成了,完整代码

class MyPromise {
    static pending = 'pending'
    static fulfilled = 'fulfilled'
    static rejected = 'rejected'
    constructor (callBack) {
        this.state = MyPromise.pending
        this.result = null
        this.error = null
        this.onResolveCallbacks = []
        this.onRejectCallbacks = []
        const resolve = (res) => {
            if (this.state === MyPromise.pending) {
                console.log(this.state + ' => ' + MyPromise.fulfilled)
                this.state = MyPromise.fulfilled
                this.result = res
                this.onResolveCallbacks.forEach(callBack => callBack())
            }
        }
        const reject = (error) => {
            if (this.state === MyPromise.pending) {
                console.log(this.state + ' => ' + MyPromise.rejected)
                this.state = MyPromise.rejected
                this.error = error
                this.onRejectCallbacks.forEach(callBack => callBack())
            }
        }
        callBack(resolve, reject)
        // console.log('result:' + this.result)
        // console.log('error:' + this.error)
    }
    then(onFulfilled, onRejected) {
        // Both onFulfilled and onRejected are function
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
        onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err }
        if (this.state === MyPromise.fulfilled) {
            onFulfilled(this.result)
        }
        if (this.state === MyPromise.rejected) {
            onRejected(this.error)
        }
        // 等待状态时暂存回调方法
        if (this.state === MyPromise.pending) {
            this.onResolveCallbacks.push(() => {
                onFulfilled(this.result)
            })
            this.onRejectCallbacks.push(() => {
                onRejected(this.error)
            })
        }
    }
}
复制代码

我们来试一下执行一下异步方法

new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 1000)
}).then(res => {
    console.log(res);
}, error => {
    console.log(error)
})
复制代码

顺利打印出来没有问题了

6fad817be6cc1311c421ecf151997c1.png

好了,本篇已经带大家实现了promise中then的基础功能,但是还不够,我们知道,原生 Promise 的 then 方法是可以链式调用的,也就是可以一直 .then().then()... 下去,下一节我会跟大家一起实现 promise 的 then 的链式调用,敬请关注!

相关文章
|
前端开发
7 # promise 的 then 方法
7 # promise 的 then 方法
81 0
|
4月前
|
前端开发 JavaScript
Vue 中 Promise 的then方法异步使用及async/await 异步使用总结
Vue 中 Promise 的then方法异步使用及async/await 异步使用总结
128 1
|
前端开发 JavaScript API
📕重学JavaScript:Promise 的then()、catch() 和 finally()
大部分时候,你要用的 Promise 对象是 Web API 或第三方 API 返回的。我们要设置 Promise 对象,让它在变成 fulfilled 的时候执行我们想要的成功的代码,而在变成 rejected 的时候执行我们想要的失败的代码。
341 0
📕重学JavaScript:Promise 的then()、catch() 和 finally()
|
前端开发 JavaScript
web前端面试高频考点——JavaScript 篇(二)【JS 异步进阶】Event Loop、then 和 catch、async/await、宏任务微任务、手撕 Promise 源码
web前端面试高频考点——JavaScript 篇(二)【JS 异步进阶】Event Loop、then 和 catch、async/await、宏任务微任务、手撕 Promise 源码
172 0
node笔记记录11promise的实例方法.then
node笔记记录11promise的实例方法.then
69 0
node笔记记录11promise的实例方法.then
|
监控 前端开发
Promise的九大方法(resolve、reject、then、catch、finally、all、allSettled、race、any)你都用过那些?
Promise的九大方法(resolve、reject、then、catch、finally、all、allSettled、race、any)你都用过那些?
|
前端开发
手写promise异步状态修改then方法返回来的结果
手写promise异步状态修改then方法返回来的结果
手写promise异步状态修改then方法返回来的结果
|
前端开发
手写Promise中then方法返回的结果或者规律
手写Promise中then方法返回的结果或者规律
手写Promise中then方法返回的结果或者规律
|
前端开发
ES6 - Promise then 嵌套
ES6 - Promise then 嵌套
169 0
|
前端开发
手写Promise自定义封装 then 函数
手写Promise自定义封装 then 函数