• 【字节前端面试题Promise】手写Promise A+


    回想起来也是有点小激动,之前面试字节前端实习的时候,一面一上来两道代码题后就是手写Promise了,当时一听到这道题,还真的有点震惊。之前确实有听说过大厂喜欢考手撕代码,没想到一上来就这么爽。

    然后呢,我也是最后写出来了这道题,这道题在以前我是有写过的,但是真的到面试的时候脑子确实是有点空白的,当时是第一次在面试的时候遇到这道题,然后我还特地的问了一下面试官,你确定吗?
    在这里插入图片描述
    面试官:嗯嗯

    好吧,那我就手撕了一下,但是之前的代码没有保存,我今天就来展现一下我手写的Promise代码

    我记得当时大概用时在15 - 20分钟,当时是面试官叫的,然后调试了一下,好像大概调试了5-6分钟。

    这个代码是今天写的,并且没有紧张的面试,所以代码质量要高过我面试时写的。

    function isFunction(func) {
      return typeof func === "function";
    }
    
    class MyPromise {
      static _PENDING = "pending";
      static _FULLFILLED = "fullfilled";
      static _REJECTED = "rejected";
    
      _handlers = [];
    
      constructor(resolver) {
        this._promiseState = MyPromise._PENDING; // Promise的状态
        this._settledValue = null; // Promise已决阶段的数据
        try {
          resolver(this._resolve.bind(this), this._reject.bind(this)); // this指向很关键
          // this.__resolve中用到了this,而在我们传入的函数参数中,这个方法的调用是走预编译过程,this指向全局对象
        } catch (error) {
          // 函数参数执行过程中抛出错误,立刻触发Promise状态为rejected
          this._changeState(MyPromise._REJECTED, error);
        }
      }
    
      _changeState(state, data) {
        if (this._promiseState !== MyPromise._PENDING) {
          // 状态发生改变之后不可更改
          return;
        }
        this._promiseState = state;
        this._settledValue = data;
        this._runHandlers(); // 改变状态后触发
        // 触发任务队列的执行有两个时间点
        // 1. 状态发生改变之后立刻触发
        // 2. then添加任务之后立刻触发,防止有些任务不是在状态改变之前添加的
      }
    
      _resolve(data) {
        this._changeState(MyPromise._FULLFILLED, data);
      }
      _reject(reason) {
        this._changeState(MyPromise._REJECTED, reason);
      }
    
      _removeHandleObj(handles, i) {
        handles.splice(i, 1);
      }
    
      _runOneHandle({ handle, resolve, reject }) {
        setTimeout(() => {
          // 宏队列模拟微队列
          try {
            const result = handle(this._settledValue);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
    
      _runHandlers() {
        if (this._promiseState === MyPromise._PENDING) {
          return;
        }
        for (let i = 0; i < this._handlers.length; i++) {
          const handleObj = this._handlers[i];
          if (handleObj.state === this._promiseState) {
            this._runOneHandle(handleObj);
          }
          this._removeHandleObj(this._handlers, i);
          i--;
        }
      }
    
      then(onResolved, onRejected) {
        return new MyPromise((resolve, reject) => {
          isFunction(onResolved) &&
            this._handlers.push({
              handle: onResolved,
              state: MyPromise._FULLFILLED,
              resolve,
              reject,
            });
          isFunction(onRejected) &&
            this._handlers.push({
              handle: onRejected,
              state: MyPromise._REJECTED,
              resolve,
              reject,
            });
          this._runHandlers();
        });
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    调试代码

    new MyPromise((resolve, reject) => {
      //   throw new Error("我是枫枫枫逸");
      setTimeout(() => {
        resolve(1);
      }, 1000);
    })
      .then(
        (data) => {
          console.log("data", data);
          return 2;
        },
        (reason) => {
          console.log("reason", reason);
        }
      )
      .then((data) => {
        console.log("data", data);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这大概就是我面试时写到的点,但是还是有缺陷的。

    有一点面试时间太紧了,没有考虑到

    在执行Promise任务时,没有考虑到如果函数返回的是一个符合Promise A+规范的对象该如何处理
    但是估计面试官没打算追问太深,就放过我了

    这是考虑到这一点之后我修改的代码

    function isFunction(func) {
      return typeof func === "function";
    }
    
    function isPromise(obj) {
      return !!(obj && typeof obj === "object" && typeof obj.then === "function");
    }
    
    class MyPromise {
      static _PENDING = "pending";
      static _FULLFILLED = "fullfilled";
      static _REJECTED = "rejected";
    
      _handlers = [];
    
      constructor(resolver) {
        this._promiseState = MyPromise._PENDING; // Promise的状态
        this._settledValue = null; // Promise已决阶段的数据
        try {
          resolver(this._resolve.bind(this), this._reject.bind(this)); // this指向很关键
          // this.__resolve中用到了this,而在我们传入的函数参数中,这个方法的调用是走预编译过程,this指向全局对象
        } catch (error) {
          // 函数参数执行过程中抛出错误,立刻触发Promise状态为rejected
          this._changeState(MyPromise._REJECTED, error);
        }
      }
    
      _changeState(state, data) {
        if (this._promiseState !== MyPromise._PENDING) {
          // 状态发生改变之后不可更改
          return;
        }
        this._promiseState = state;
        this._settledValue = data;
        this._runHandlers(); // 改变状态后触发
        // 触发任务队列的执行有两个时间点
        // 1. 状态发生改变之后立刻触发
        // 2. then添加任务之后立刻触发,防止有些任务不是在状态改变之前添加的
      }
    
      _resolve(data) {
        this._changeState(MyPromise._FULLFILLED, data);
      }
      _reject(reason) {
        this._changeState(MyPromise._REJECTED, reason);
      }
    
      _removeHandleObj(handles, i) {
        handles.splice(i, 1);
      }
    
      _runOneHandle({ handle, resolve, reject }) {
        setTimeout(() => {
          // 宏队列模拟微队列
          try {
            const result = handle(this._settledValue);
            if (isPromise(result)) {
              // 如果返回的是一个Promise
              // 那么返回的Promise的状态应该与该Promise的状态保持一致
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          } catch (error) {
            reject(error);
          }
        });
      }
    
      _runHandlers() {
        if (this._promiseState === MyPromise._PENDING) {
          return;
        }
        for (let i = 0; i < this._handlers.length; i++) {
          const handleObj = this._handlers[i];
          if (handleObj.state === this._promiseState) {
            this._runOneHandle(handleObj);
          }
          this._removeHandleObj(this._handlers, i);
          i--;
        }
      }
    
      then(onResolved, onRejected) {
        return new MyPromise((resolve, reject) => {
          isFunction(onResolved) &&
            this._handlers.push({
              handle: onResolved,
              state: MyPromise._FULLFILLED,
              resolve,
              reject,
            });
          isFunction(onRejected) &&
            this._handlers.push({
              handle: onRejected,
              state: MyPromise._REJECTED,
              resolve,
              reject,
            });
          this._runHandlers();
        });
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    手写Promise之后我觉得对Promise的了解也更加深刻。

    当然我写的肯定跟大佬们的不能比,只希望能提供一个思考的方向,觉得有帮助的别忘了点赞哦~~
    在这里插入图片描述

  • 相关阅读:
    新房装修,自带的线路有必更要换吗
    快速入门Git
    ssm基于java的大学生成绩管理系统毕业设计源码130930
    kubeasz一键部署k8s集群
    【Android开发】内存泄露
    Spring系列五:Spring怎么解决循环依赖
    postgresql参数优化
    (项目实战)RocketMQ5.0延迟消息在聚合支付系统中的应用
    git 分支代码合并到master主分支上或者master合并到开发分支
    优化 | Management Science 7-8月文章精选: 信息系统中的运筹学
  • 原文地址:https://blog.csdn.net/weixin_45696837/article/details/126151004