前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >带你手写Promise身上的几个方法,拷打面试官

带你手写Promise身上的几个方法,拷打面试官

作者头像
用户6256742
发布2024-06-30 09:33:51
620
发布2024-06-30 09:33:51
举报
文章被收录于专栏:网络日志网络日志

前言

Promise的手写是面试中一个常考的考点。希望我的文章能够帮到大家,在被问到Promise时能够露出一个自信的微笑。

constructor

首先来写一个Promise的构造器,这有帮助于我们了解Promise的内部结构和他各个方法的底层原理。

代码语言:javascript
复制
class myPromise{
constructor(executor){
    this.state = 'pending' // 记录promise的状态,pending...等
    this.value = undefined // resolve传递的值
    this.reason = undefined // reject传递的值
    this.onFullfilledCallback = [] // resovle的回调函数
    this.onRejectedCallback = [] // rejected的回调函数
    const resolve = (value)=>{
        if(this.state === 'pending'){
            this.state = 'fulfilled'// 判断当前对象状态
            this.value = value
            this.onFullfilledCallback.forEach(callback=>callback(value))
        }
    }
    const reject = (reason)=>{
        if(this.state === 'pending'){
            this.state = 'rejected'// 判断当前对象状态
            this.reason = reason
            this.onRejectedCallback.forEach(callback=>callback(reason))
        }
    }
    executor(resolve, reject) // 执行器函数
}
}

这种手写的话我们都要想一想我们平时使用promise有哪些特点。首先我们知道

  • promise有三种状态,pending,fulfilled,reject
  • promise状态一旦修改无法二次修改(为了确认异步操作的正确性)
  • resolve和reject可以接受一个回调函数 基于这些我们就写出了以上这些代码。

then

代码语言:javascript
复制
then(onFulfilled,onRejected){
// 判断是否传递了一个回调参数
  onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        const newPromise = new myPromise((resolve, reject) => {
            // 考虑onFullfilled,onRejected
            if (this.state === 'fulfilled') {// then前面的对象状态已经变更
                setTimeout(() => {// 模拟异步但是模拟不了微任务
                    try {
                        const result = onFullfilled(this.value)
                        resolve(result)
                    } catch (e) {
                        reject(e)
                    }
                });
            }
            if (this.state === 'rejected') {
                setTimeout(() => {// 模拟异步但是模拟不了微任务
                    try {
                        const result = onRejected(this.reason)
                        resolve(result)
                    } catch (e) {
                        reject(e)
                    }
                });
            }
            if (this.state === 'pending') {
                this.onFullfilledCallback.push((value) => {
                    setTimeout(() => {
                        try {
                            const result = onFullfilled(value)
                            resolve(result)
                        } catch (error) {
                            reject(error)
                        }
                    });
                })
                this.onRejectedCallback.push((reason) => {
                    setTimeout(() => {
                        try {
                            const result = onRejected(reason)
                            resolve(result)
                        } catch (error) {
                            reject(error)
                        }
                    });
                })
            }
        })
        return newPromise
}
  • then中可以接受两个参数,当上一个promise对象为fulfilled时调用第一个回调函数,rejected调用第二个回调函数
  • then需要返回一个新的promise对象并且返回和上一个promise对象resolve或者rejected对应的值

catch

代码语言:javascript
复制
catch(onRejected) {
        this.then(null, onRejected)
    }

race

代码语言:javascript
复制
 // race 只找最快的,无论是resolve和rejected都只取最快的一个
    static race(promises) {
        return new myPromise((resolve, reject) => {
            promises.forEach(promise => {
                // promise的状态是不是fulfilled
                promise.then((value) => {
                    resolve(value)
                }, (reason) => {
                    reject(reason)
                })
            })
        })
    }
  • race会返回一个新的promise对象
  • race接受一个数组为参数,数组每一个元素都要是一个promise对象
  • race会取数组中速度最快的一个为结果并返回,无论是promise还是rejected

all

代码语言:javascript
复制
// all 当所有的都是resolve就会以数组形式返回所有的值,有一个reject直接reject
    static all(promises) {
        return new myPromise((resolve, reject) => {
            let count = 0
            let arr = []
            // 判断数组中所有的promise状态是否都为fulfilled
            promises.forEach((promise, i) => {
                promise.then((value) => {
                    count++
                    arr[i] = value
                    if (count === promise.length) {
                        resolve(arr)
                    }
                }, (reason) => {
                    reject(reason)
                })
            })
        })
    }
  • all也会返回一个新的promise对象且也接受一个元素全为promise的数组为参数
  • 当数组中所有元素的状态都为resolve时就返回所有的数组元素,有一个为rejected就返回那一个rejected的对象,无论哪种情况都要给返回的peomise对象设置对应的状态。

any

代码语言:javascript
复制
// 只要有一个能resolve就直接resolve,全部reject才reject
    static any(promises) {
        return new myPromise((resolve, reject) => {
            let count = 0
            let arr = []
            promises.forEach((promise, i) => {
                promise.then((value) => {
                    resolve(value)
                }, (reason) => {
                    count++
                    arr[i] = reason
                    if (count === promises.length) {
                        reject(new AggregateError(arr, 'All promise were rejected'))
                    }
                })
            })
        })
    }
  • any和all相反,只要有一个元素状态为resolve就直接返回那一个resolve对象并用一个新的promise对象包裹且设置对应的状态
  • 全为rejected则返回整个数组也是promise对象包裹且状态设置为rejected

finally

代码语言:javascript
复制
 // finally在前一个promise对象结束时,无论是fulfilled还是rejected都会调用内部回调
    finally(callback) {
        return this.then(() => {
            (value) => { return Promise.resolve(callback()).then(() => value) }
        }, () => {
            (reason) => { return Promise.resolve(callback()).then(() => reason) }
        })
    }
  • finally对于上一个promise对象无论他的值为什么都要调用其回调函数
  • 并且要返回其对应的resolve或者rejected对应的值

allSettled

代码语言:javascript
复制
 static allSettled(promises) {
        let arr = []
        let count = 0
        return new myPromise((resolve, reject) => {
            promises.forEach((promise, i) => {
                promise.then((value) => {
                    arr[i] = { status: 'fulfilled', vlaue: value }
                }, (reason) => {
                    arr[i] = { status: 'rejected', reason: reason }
                }).finally(() => {
                    count++
                    // 所有promise状态都变更
                    if (count === promises.length) {
                        resolve(arr)
                    }
                })
            })
        })
    }
  • allSettled接受一个数组为参数
  • 当数组中所有元素的状态都发生变更时才会调用其内部的回调并返回一个新的promise对象
  • 返回的对象只要发生状态变更一定是fulfilled

尾声

Promise主要的几个手写方法就是这样,对于这种手写题我们一定要思考我们平时使用时有哪些特征,并根据这些特征一步步编写我们的代码,最后就能完全成型。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • constructor
      • then
        • catch
          • race
            • all
              • any
                • finally
                  • allSettled
                  • 尾声
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档