深入浅出JS—18 手把手实现一个Promise类

Promise类的实现是高级面试中常考的题目,由于Promise包含的方法比较多,一般写到Promise1.0或者2.0版本已经能够满足面试要求了,不过全面深入理解Promise对于工作中Promise的使用也非常有帮助

Promise1.0版本⭐

实现constrcutor函数,then函数

  • Promise是一个类,要创建对象就要调用new关键字,传入的参数为一个函数executor
  • executor函数有两个入参,为两个回调函数resolve,reject,它们已经在Promise类内部实现好了
  • executor函数传入之后会被立即执行
class MyPromise {
  // 构造函数
  constructor(executor) {
    const resolve = (value) => {
      this.value = value;
    };
    const reject = (reason) => {
      this.reason = reason;
    };
    // 立即执行函数
    executor(resolve, reject);
  }
}

then基本实现

class MyPromise {
  constructor(executor) {
    const resolve = (value) => {
      this.value = value;
    };
    const reject = (reason) => {
      this.reason = reason;
    };
    executor(resolve, reject);
  }
  
  // then方法
  then(onFulfilled, onRejected) {
    onFulfilled(this.value);
    onRejected(this.reason);
  }
}

/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("resolve value");
    reject("reject reason");
  }, 100);
});

promise.then(
  (res) => { console.log("res:", res); }, 
  (err) => { console.log("err:", err); }
);
// undefined undefined

问题:顺序执行到then方法时,setTimeout函数还没执行回调,this.value和this.reason还没为undefined


改进onFulfilled(this.value)onRejected(this.reason)入参不应该在then方法中调用,应该在resolve和reject中调用
每次对代码改进的关键步骤都用⭐进行了标识

class MyPromise {
  constructor(executor) {
    const resolve = (value) => {
      this.value = value;
      this.onFulfilled(this.value); // ⭐
    };
    const reject = (reason) => {
      this.reason = reason;
      this.onRejected(this.reason); // ⭐
    };
    executor(resolve, reject);
  }

  // then方法
  then(onFulfilled, onRejected) {
    this.onFulfilled = onFulfilled; // ⭐
    this.onRejected = onRejected; // ⭐
  }
}
/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
    resolve("resolve value");
    reject("reject reason");
});

promise.then(
  (res) => { console.log("res:", res); }, 
  (err) => { console.log("err:", err); }
);
// 报错:TypeError: this.onFulfilled is not a function

问题:调用this.onFulfilled时,还没执行到then,所以还是undefined


改进:必须更改顺序,先执行then,拿到回调函数,然后再在resolve、reject函数中调用回调函数
重点queueMicrotask() 主动调用异步函数,来更改代码的执行顺序

class MyPromise {
  // 构造函数
  constructor(executor) {
    const resolve = (value) => {
      this.value = value;
      queueMicrotask(() => this.onFulfilled(this.value));// ⭐
    };
    const reject = (reason) => {
      this.reason = reason;
      queueMicrotask(() => this.onRejected(this.reason));// ⭐
    };
    executor(resolve, reject);
  }

  // then方法
  then(onFulfilled, onRejected) {
    this.onFulfilled = onFulfilled;
    this.onRejected = onRejected;
  }
}

问题:resolve和reject只能执行一个


改进:引入Promise状态变量
重点:对于三种固定的状态,一般使用枚举来书写(ts),没有枚举就定义常量

const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

class MyPromise {
  // 构造函数
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING;

    const resolve = (value) => {
      if (this.status !== PROMISE_STATUS_PENDING) return; // ⭐
      this.status = PROMISE_STATUS_FULFILLED;
      this.value = value;
      queueMicrotask(() => {
        this.onFulfilled(this.value);
      });
    };

    const reject = (reason) => {
      if (this.status !== PROMISE_STATUS_PENDING) return; //⭐
      this.status = PROMISE_STATUS_REJECTED;
      this.reason = reason;
      queueMicrotask(() => {
        this.onRejected(this.reason);
      });
    };

    executor(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    this.onFulfilled = onFulfilled;
    this.onRejected = onRejected;
  }
}

Promise2.0版本⭐

then多次调用

/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
    resolve("resolve value");
    reject("reject reason");
});

promise.then(
  (res) => { console.log("res:", res); }, 
  (err) => { console.log("err:", err); }
);

promise.then(
  (res) => { console.log("res1:", res); }, 
  (err) => { console.log("err1:", err); }
);

// 宏任务在微任务之后,数组已经遍历执行结束了,怎么办
setTimeout(() => {
  promise.then(
  (res) => { console.log("res2:", res); }, 
  (err) => { console.log("err2:", err); }
  );
}, 100);

问题
1 由于this.onFulfilled函数赋值是异步进行的,所以顺序执行的最后一个then方法会覆盖之前的,将自己的回调onFulfilled赋值给this.onFulfilled函数
2 若then回调是在异步函数中,在微任务之后,无法加入回调函数队列中执行


改进
1 采用数组存取回调函数
2 在微任务之后,说明已经拿到了this.value和this.reason,那么回调函数在then函数中直接执行即可

const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

class MyPromise {
  // 构造函数
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING;
    this.onFulfilledFns = [];//⭐ 数组保存
    this.onRejectedFns = [];
    
    const resolve = (value) => {
      if (this.status !== PROMISE_STATUS_PENDING) return;
      queueMicrotask(() => {
        if (this.status !== PROMISE_STATUS_PENDING) return; //⭐ 防止resolve和reject都执行
        this.value = value;
        this.onFulfilledFns.forEach((fn) => fn(this.value));
        this.status = PROMISE_STATUS_FULFILLED;
      });
    };

    const reject = (reason) => {
      if (this.status !== PROMISE_STATUS_PENDING) return;
      queueMicrotask(() => {
        if (this.status !== PROMISE_STATUS_PENDING) return;
        this.reason = reason;
        this.onRejectedFns.forEach((fn) => fn(this.reason));
        this.status = PROMISE_STATUS_REJECTED;
      });
    };

    executor(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
      onFulfilled(this.value); //⭐状态已经确定,说明微任务执行完毕,this.value已经有值,直接执行就可以 
    }

    if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
      onRejected(this.reason);
    }

    if (this.status === PROMISE_STATUS_PENDING) {
      onFulfilled && this.onFulfilledFns.push(onFulfilled);//⭐ 加入数组
      onRejected && this.onRejectedFns.push(onRejected);
    }
  }
}

then链式调用

then能链式调用,说明then函数能够返回一个Promise对象
重点
1 如何拿到回调函数的结果?再包裹一层回调函数
2 reject的函数的返回值也是一个Promise对象,和resolve没有区别
3 如果要在reject抛出出错,需要用try-catch捕获

// 工具函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
  try {
    const result = execFn(value);
    resolve(result);
  } catch (err) {
    reject(err);
  }
}

 then(onFulfilled, onRejected) {
 	//⭐ then返回一个MyPromise对象
    return new MyPromise((resolve, reject) => {
      if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
      }

      if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
        execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
      }

      if (this.status === PROMISE_STATUS_PENDING) {
       //⭐push到数组的函数外层又包裹了一个回调函数,为了得到返回结果
        onFulfilled &&
          this.onFulfilledFns.push(() => {
            execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
          });
        onRejected &&
          this.onRejectedFns.push(() => {
            execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
          });
      }
    });
  }

Promise3.0版本

实现catch对象方法,finally对象方法

  • catch方法
    基于then方法实现,由于catch是在then后调用,实质上是then返回的promise对象调用的then方法,为了捕获原始的promise对象抛出的reject,需要将错误抛出
then(onFulfilled, onRejected) {
 	onRejected = onRejected || (err=> {throw new Error(err)}); // 将错误抛出去
 	
    return new MyPromise((resolve, reject) => {
     /*原来代码*/
    });
  }
  
 catch(onRejected) {
    return this.then(undefined, onRejected);
  }
  • finally方法
  finally(onFinally) {
    return this.then(onFinally, onFinally);
  }

Promise4.0版本

实现类静态方法resolve、reject

  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value);
    });
  }

  static reject(reason) {
    return new MyPromise((resoble, reject)=>{
      reject(reason);
    })
  }

Promise5.0版本

实现类方法all allSettled race any

重点:什么时机调用resolve和reject

  • all
  static all(promises) {
    const results = [];
    let i = 0;
    // 如何让保存取结果与顺序有关,与返回顺序无关
    return new MyPromise((resolve, reject) => {
      promises.forEach((p, index) => {
        p.then(
          (res) => {
            results[index] = res;
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }
  • allSettled
  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let i = 0;
      promises.forEach((p, index) => {
        p.then(
          (res) => {
            results[index] = { status: PROMISE_STATUS_FULFILLED, value11: res };
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          },
          (err) => {
            results[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          }
        );
      });
    });
  }
  • race
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(
          resolve,
          reject
        );
      });
    });
  }
  • any
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const reasons = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reasons.push(err);
            if (reasons.length === promises.length) {
              reject(reasons);
            }
          }
        );
      });
    });
  }

代码整合

const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

function execFunctionWithCatchError(execFn, value, resolve, reject) {
  try {
    const result = execFn(value);
    resolve(result);
  } catch (err) {
    reject(err);
  }
}

class MyPromise {
  // 构造函数
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING;
    this.onFulfilledFns = [];
    this.onRejectedFns = [];

    const resolve = (value) => {
      if (this.status !== PROMISE_STATUS_PENDING) return;

      queueMicrotask(() => {
        if (this.status !== PROMISE_STATUS_PENDING) return;
        this.value = value;
        this.onFulfilledFns.forEach((fn) => fn(this.value));
        this.status = PROMISE_STATUS_FULFILLED;
      });
    };

    const reject = (reason) => {
      if (this.status !== PROMISE_STATUS_PENDING) return;
      queueMicrotask(() => {
        if (this.status !== PROMISE_STATUS_PENDING) return;
        this.reason = reason;
        this.onRejectedFns.forEach((fn) => fn(this.reason));
        this.status = PROMISE_STATUS_REJECTED;
      });
    };

    executor(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    onRejected =
      onRejected ||
      ((err) => {
        throw new Error(err);
      });
    onFulfilled = onFulfilled || ((value) => value);

    return new MyPromise((resolve, reject) => {
      if (this.status === PROMISE_STATUS_FULFILLED) {
        execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
      }

      if (this.status === PROMISE_STATUS_REJECTED) {
        execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
      }

      if (this.status === PROMISE_STATUS_PENDING) {
        this.onFulfilledFns.push(() => {
          execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
        });

        this.onRejectedFns.push(() => {
          execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  finally(onFinally) {
    return this.then(onFinally, onFinally);
  }

  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value);
    });
  }

  static reject(reason) {
    return new MyPromise((resoble, reject) => {
      reject(reason);
    });
  }

  static all(promises) {
    const results = [];
    let i = 0;
    return new MyPromise((resolve, reject) => {
      promises.forEach((p, index) => {
        p.then(
          (res) => {
            results[index] = res;
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }

  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let i = 0;
      promises.forEach((p, index) => {
        p.then(
          (res) => {
            results[index] = { status: PROMISE_STATUS_FULFILLED, value11: res };
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          },
          (err) => {
            results[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
            i++;
            if (i === promises.length) {
              resolve(results);
            }
          }
        );
      });
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(resolve, reject);
      });
    });
  }
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const reasons = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reasons.push(err);
            if (reasons.length === promises.length) {
              reject(reasons);
            }
          }
        );
      });
    });
  }
}

// 使用
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    // resolve("resolve value");
    reject("reject reason");
  }, 100);
});

promise
  .then((res) => {
    console.log("res:", res);
    return "aaa";
  })
  .catch((err) => {
    console.log("err:", err);
  });

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深入浅出Python机器学习》是一本介绍Python机器学习的入门级书籍。本书适合初学者,通过简洁明了的语言和实用的示例来引导读者学习机器学习的基本原理和Python编程技巧。 这本书首先介绍了机器学习的基本概念和应用场景。作者通过举例解释了监督学习、无监督学习和半监督学习等机器学习方法的基本原理和应用领域。读者可以通过这些例子了解到机器学习在图像识别、文本分、推荐系统等领域的应用。 接下来,本书详细介绍了Python机器学习框架的使用。作者详细介绍了NumPy、Pandas和Scikit-learn等常用的Python机器学习库的基本功能和用法,读者可以通过这些库来实现和优化自己的机器学习算法。 在学习机器学习算法的过程,本书给出了大量的机器学习算法实例。作者通过手把手地讲解,实战展示了线性回归、决策树、支持向量机等常见的机器学习算法的原理和应用。读者可以通过这些实例学习到如何选择并应用不同的机器学习算法解决实际问题。 此外,本书还介绍了交叉验证、特征选择和模型评估等机器学习相关的技术和方法。这些内容为读者提供了更全面的机器学习知识体系,帮助读者更好地理解和应用机器学习算法。 总的来说,《深入浅出Python机器学习》是一本结合理论与实践的实用教材,对于想要了解机器学习并使用Python实现算法的读者来说是一本很好的参考书籍。它将机器学习的基本原理和Python编程技巧有机地结合在一起,帮助读者快速入门并能够应用机器学习算法解决实际问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值