两年前端经验还不会手写Promise?

2024年 3月 7日 74.0k 0

什么是promise?

当我们处理异步操作时,我们经常需要进行一系列的操作,如请求数据、处理数据、渲染UI等。在过去,这些操作通常通过回调函数来处理,但是回调函数嵌套过多会导致代码难以维护,产生回调地狱(Callback Hell)。Promise就是一种用于解决异步编程问题的解决方案。

概念?

Promise是一种代表异步操作最终完成或失败的对象。它是ES6中新增的语法特性,通过Promise对象,可以更加优雅地处理异步操作。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。一旦Promise的状态发生改变,就不会再变。

Promise的作用:

  • 异步操作的管理: Promise提供了一种标准的方式来管理异步操作,使得代码更加清晰易读。
  • 解决回调地狱问题: Promise的链式调用(Chaining)可以避免多层嵌套的回调函数,使代码结构更加清晰。
  • 错误处理: Promise提供了统一的错误处理机制,通过catch方法可以捕获Promise链中的错误,避免了未捕获的异常。
  • 并行和串行执行: Promise可以串行或并行执行多个异步操作,并通过Promise.all和Promise.race等方法来管理多个Promise实例的状态。
  • Promise的方法:

  • then(onFulfilled, onRejected): then方法用于注册Promise的成功和失败回调,并返回一个新的Promise,可以实现链式调用。
  • catch(onRejected): catch方法用于捕获Promise链中的错误,并返回一个新的Promise,用于处理错误。
  • finally(onFinally): finally方法用于注册一个回调函数,无论Promise的状态如何都会被调用。
  • Promise.resolve(value): Promise.resolve方法用于将一个值包装成Promise对象,如果参数是Promise实例,则直接返回该实例。
  • Promise.reject(reason): Promise.reject方法用于返回一个状态为rejected的Promise对象,并将指定的原因传递给Promise的回调函数。
  • Promise.all(iterable): Promise.all方法用于将多个Promise实例包装成一个新的Promise实例,当所有Promise实例的状态都变为fulfilled时,新的Promise的状态才变为fulfilled;当其中一个Promise实例的状态变为rejected时,新的Promise的状态就变为rejected。
  • Promise.race(iterable): Promise.race方法用于将多个Promise实例包装成一个新的Promise实例,当其中一个Promise实例的状态发生改变时,新的Promise的状态就跟着改变。
  • Promise.allSettled(iterable): Promise.allSettled方法用于将多个Promise实例包装成一个新的Promise实例,无论这些Promise的状态如何,最终返回的Promise实例的状态都会变为fulfilled,返回的结果是一个包含所有Promise的状态和结果的数组。
  • 实现Promise的重点

    如果要手写Promise,那就需要先理清楚重点,然后实现主,要集中在以下几个方面:

  • 状态管理: Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。在Promise的生命周期中,它会从pending状态转变为fulfilled或rejected状态,一旦状态改变就不可再变。状态的变化由Promise的执行器函数中的resolve和reject函数触发。
  • 链式调用: Promise允许通过then方法链式调用,每次调用then都会返回一个新的Promise实例,以实现更加灵活的异步操作。通过链式调用,可以串联多个异步操作,并在每个操作完成后执行特定的处理逻辑。
  • 错误处理: Promise提供了catch方法用于捕获Promise链中的错误。在Promise链中,如果某个Promise发生了rejected状态,它会沿着链路向下传递,直到被catch方法捕获到错误,或者如果没有捕获到错误,则会导致未捕获的异常。
  • 异步执行: Promise的then方法中的回调函数会在当前执行栈执行完成后,通过事件循环机制被放入下一个事件循环中执行,这样可以保证回调函数总是在当前代码执行完成后执行,从而实现异步操作。
  • 解决回调地狱问题: Promise的链式调用可以解决回调地狱(Callback Hell)的问题,使得代码更加清晰易读。通过Promise,可以更加优雅地处理多个异步操作的串行或并行执行,避免了深度嵌套的回调函数。
  • 实现Promise

    在知道Promise的概念以及重点之后,我们来简单实现一下:

    class MyPromise {
      constructor(executor) {
        // 初始化Promise的状态为pending
        this.state = 'pending';
        // 存储Promise的成功值
        this.value = undefined;
        // 存储Promise的失败原因
        this.reason = undefined;
        // 存储成功状态下的回调函数数组
        this.onResolvedCallbacks = [];
        // 存储失败状态下的回调函数数组
        this.onRejectedCallbacks = [];
    
    
        // 定义resolve函数,用于将Promise状态从pending改变为fulfilled
        const resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            // 执行成功状态下的回调函数数组中的每个回调函数
            this.onResolvedCallbacks.forEach(callback => callback());
          }
        };
    
    
        // 定义reject函数,用于将Promise状态从pending改变为rejected
        const reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            // 执行失败状态下的回调函数数组中的每个回调函数
            this.onRejectedCallbacks.forEach(callback => callback());
          }
        };
    
    
        try {
          // 执行executor函数,并将resolve和reject函数作为参数传递给executor
          executor(resolve, reject);
        } catch (error) {
          // 如果executor执行过程中发生了错误,则将Promise状态改变为rejected
          reject(error);
        }
      }
    
    
      // then方法用于注册Promise的成功和失败回调,并返回一个新的Promise
      then(onFulfilled, onRejected) {
        // 创建一个新的Promise实例
        const newPromise = new MyPromise((resolve, reject) => {
          // 当前Promise的状态为fulfilled时
          if (this.state === 'fulfilled') {
            // 异步执行onFulfilled回调函数,并处理返回值result
            setTimeout(() => {
              try {
                const result = onFulfilled(this.value);
                // 将返回值result传递给resolvePromise函数,处理新Promise的状态
                resolvePromise(newPromise, result, resolve, reject);
              } catch (error) {
                // 如果执行onFulfilled回调函数过程中发生了错误,则将新Promise的状态改为rejected
                reject(error);
              }
            }, 0);
          }
    
    
          // 当前Promise的状态为rejected时
          if (this.state === 'rejected') {
            // 异步执行onRejected回调函数,并处理返回值result
            setTimeout(() => {
              try {
                const result = onRejected(this.reason);
                // 将返回值result传递给resolvePromise函数,处理新Promise的状态
                resolvePromise(newPromise, result, resolve, reject);
              } catch (error) {
                // 如果执行onRejected回调函数过程中发生了错误,则将新Promise的状态改为rejected
                reject(error);
              }
            }, 0);
          }
    
    
          // 当前Promise的状态为pending时
          if (this.state === 'pending') {
            // 将成功和失败回调函数分别添加到对应的回调函数数组中
            this.onResolvedCallbacks.push(() => {
              // 异步执行成功回调函数,并处理返回值result
              setTimeout(() => {
                try {
                  const result = onFulfilled(this.value);
                  // 将返回值result传递给resolvePromise函数,处理新Promise的状态
                  resolvePromise(newPromise, result, resolve, reject);
                } catch (error) {
                  // 如果执行成功回调函数过程中发生了错误,则将新Promise的状态改为rejected
                  reject(error);
                }
              }, 0);
            });
    
    
            this.onRejectedCallbacks.push(() => {
              // 异步执行失败回调函数,并处理返回值result
              setTimeout(() => {
                try {
                  const result = onRejected(this.reason);
                  // 将返回值result传递给resolvePromise函数,处理新Promise的状态
                  resolvePromise(newPromise, result, resolve, reject);
                } catch (error) {
                  // 如果执行失败回调函数过程中发生了错误,则将新Promise的状态改为rejected
                  reject(error);
                }
              }, 0);
            });
          }
        });
    
    
        // 返回新的Promise实例
        return newPromise;
      }
    }
    
    
    // resolvePromise函数用于处理then方法中回调函数返回的结果
    function resolvePromise(newPromise, result, resolve, reject) {
      // 如果新的Promise和返回值是同一个对象,则抛出错误
      if (newPromise === result) {
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
    
    
      // 如果返回值是Promise实例,则等待该Promise的状态改变,并根据其状态决定新Promise的状态
      if (result instanceof MyPromise) {
        result.then(resolve, reject);
      } else {
        // 如果返回值不是Promise实例,则将返回值传递给resolve函数,将新Promise的状态改变为fulfilled
        resolve(result);
      }
    }

    这段代码实现了一个非常基础的Promise,主要有以下几个部分:

  • 构造函数:
  • 构造函数接受一个执行器函数作为参数,在构造函数内部定义了resolve和reject函数,并执行了执行器函数。执行器函数接受两个参数,分别是resolve和reject,它们分别用于将Promise状态从pending改变为fulfilled和rejected。

    执行器函数中通过try...catch块捕获可能的异常,并在捕获到异常时将Promise状态改变为rejected。

  • then方法:
  • then方法用于注册Promise的成功和失败回调,并返回一个新的Promise。它接受两个参数,分别是成功回调onFulfilled和失败回调onRejected。

    在then方法内部,根据当前Promise的状态(pending、fulfilled、rejected),分别处理执行成功和执行失败的逻辑,并在异步环境下使用setTimeout确保执行顺序。

    如果then方法中的回调函数返回了一个Promise,则等待该Promise的状态改变,并根据其状态决定新的Promise的状态。

  • resolvePromise函数:

  • resolvePromise函数用于处理then方法中回调函数返回的结果。如果结果是一个Promise,则等待该Promise的状态改变,并根据其状态决定新的Promise的状态。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论