深入理解 Promise:使用指南与手动实现

Promise 是 JavaScript 中处理异步操作的核心工具之一。它提供了一种更优雅的方式来管理异步代码,避免了回调地狱(Callback Hell)。本文将分为两部分:第一部分介绍 Promise 的使用与创建指南,第二部分手动实现一个简化版的 Promise,帮助你深入理解其工作原理。

第一部分:Promise 的使用与创建指南

1. 什么是 Promise?

Promise 是一个表示异步操作最终完成(或失败)及其结果值的对象。它有三种状态:

  1. Pending(等待中):初始状态,既不是成功,也不是失败。

  2. Fulfilled(已成功):操作成功完成。

  3. Rejected(已失败):操作失败。

Promise 的核心功能是通过 thencatch 和 finally 方法处理异步操作的结果。

2. 创建 Promise

你可以通过 new Promise() 构造函数来创建一个 Promise 对象。Promise 构造函数接受一个函数作为参数,这个函数有两个参数:resolve 和 reject,它们都是函数。

  • resolve(value):当异步操作成功时调用,并将结果传递给 then 方法。

  • reject(error):当异步操作失败时调用,并将错误传递给 catch 方法。

const myPromise = new Promise((resolve, reject) => {
  // 模拟异步操作
  setTimeout(() => {
    const success = true; // 假设这是一个异步操作的结果
    if (success) {
      resolve("操作成功!");
    } else {
      reject("操作失败!");
    }
  }, 1000);
});

3. 使用 Promise

创建 Promise 后,你可以使用 .then().catch() 和 .finally() 方法来处理 Promise 的结果。

  • .then(onFulfilled, onRejected):当 Promise 被 resolve 时调用 onFulfilled,当 Promise 被 reject 时调用 onRejected

  • .catch(onRejected):当 Promise 被 reject 时调用 onRejected

  • .finally(onFinally):无论 Promise 是 resolve 还是 reject,都会调用 onFinally

myPromise
  .then((result) => {
    console.log(result); // 输出: "操作成功!"
  })
  .catch((error) => {
    console.error(error); // 输出: "操作失败!"
  })
  .finally(() => {
    console.log("操作完成。");
  });

4. 链式调用

Promise 支持链式调用,你可以在一个 then 方法中返回一个新的 Promise,然后在下一个 then 中处理它。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(10);
  }, 1000);
});

promise1
  .then((value) => {
    console.log(value); // 输出: 10
    return value * 2;
  })
  .then((value) => {
    console.log(value); // 输出: 20
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(value + 5);
      }, 1000);
    });
  })
  .then((value) => {
    console.log(value); // 输出: 25
  })
  .catch((error) => {
    console.error(error);
  });

5. Promise 的静态方法

Promise 提供了一些静态方法,用于处理多个 Promise

  • Promise.resolve(value):返回一个以给定值解析的 Promise 对象。

  • Promise.reject(error):返回一个以给定原因拒绝的 Promise 对象。

  • Promise.all(iterable):当所有 Promise 都成功时返回一个包含所有结果的数组,如果有一个失败则立即返回失败的原因。

  • Promise.race(iterable):返回第一个完成(无论是成功还是失败)的 Promise 的结果。

const promise2 = Promise.resolve("立即解析");
const promise3 = Promise.reject("立即拒绝");

Promise.all([promise1, promise2])
  .then((values) => {
    console.log(values); // 输出: [10, "立即解析"]
  })
  .catch((error) => {
    console.error(error);
  });

Promise.race([promise1, promise2])
  .then((value) => {
    console.log(value); // 输出: "立即解析"
  })
  .catch((error) => {
    console.error(error);
  });

第二部分:手动实现一个简化版的 Promise

我们将实现一个简化版的 Promise,支持以下功能:

  1. 基本的状态管理(pendingfulfilledrejected)。

  2. then 方法:处理成功和失败的回调。

  3. catch 方法:处理失败的回调。

  4. 静态方法:resolverejectall 和 race

1. 构造函数

Promise 的构造函数接受一个执行器函数(executor),该函数有两个参数:resolve 和 reject

class MyPromise {
  constructor(executor) {
    this.status = 'pending'; // 初始状态
    this.value = undefined;   // 成功时的值
    this.reason = undefined; // 失败时的原因
    this.onFulfilledCallbacks = []; // 成功回调队列
    this.onRejectedCallbacks = [];  // 失败回调队列

    const resolve = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled'; // 状态改为成功
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected'; // 状态改为失败
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      // 执行传入的函数
      executor(resolve, reject);
    } catch (error) {
      // 如果执行过程中出错,直接 reject
      reject(error);
    }
  }
}

2. then 方法

then 方法用于注册成功和失败的回调,并返回一个新的 Promise,以支持链式调用。

then(onFulfilled, onRejected) {
  // 如果 onFulfilled 不是函数,则提供一个默认函数
  onFulfilled =
    typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
  // 如果 onRejected 不是函数,则提供一个默认函数
  onRejected =
    typeof onRejected === 'function'
      ? onRejected
      : (reason) => {
          throw reason;
        };

  // 返回一个新的 Promise,支持链式调用
  const promise2 = new MyPromise((resolve, reject) => {
    if (this.status === 'fulfilled') {
      // 如果当前状态是成功,异步执行 onFulfilled
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          // 处理返回值
          this.resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else if (this.status === 'rejected') {
      // 如果当前状态是失败,异步执行 onRejected
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          // 处理返回值
          this.resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else if (this.status === 'pending') {
      // 如果当前状态是 pending,将回调放入队列
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });
    }
  });

  return promise2;
}

3. catch 方法

catch 方法是 then 的语法糖,专门用于处理失败的回调。

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

4. 静态方法

我们实现了以下静态方法:

  • MyPromise.resolve:返回一个已解析的 Promise

  • MyPromise.reject:返回一个已拒绝的 Promise

  • MyPromise.all:等待所有 Promise 完成。

  • MyPromise.race:返回第一个完成的 Promise。 

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

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

static all(promises) {
  return new MyPromise((resolve, reject) => {
    const results = [];
    let count = 0;
    promises.forEach((promise, index) => {
      MyPromise.resolve(promise).then(
        (value) => {
          results[index] = value;
          count++;
          if (count === promises.length) {
            resolve(results);
          }
        },
        (reason) => {
          reject(reason);
        }
      );
    });
  });
}

static race(promises) {
  return new MyPromise((resolve, reject) => {
    promises.forEach((promise) => {
      MyPromise.resolve(promise).then(
        (value) => {
          resolve(value);
        },
        (reason) => {
          reject(reason);
        }
      );
    });
  });
}

 5. 使用示例

const p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

p1.then((value) => {
  console.log(value); // 输出: "成功"
  return '新的值';
})
  .then((value) => {
    console.log(value); // 输出: "新的值"
  })
  .catch((error) => {
    console.error(error);
  });

// 使用静态方法
MyPromise.all([p1, MyPromise.resolve('立即解析')]).then((values) => {
  console.log(values); // 输出: ["成功", "立即解析"]
});

MyPromise.race([p1, MyPromise.resolve('立即解析')]).then((value) => {
  console.log(value); // 输出: "立即解析"
});

总结

通过本文,我们学习了 Promise 的基本用法,包括创建、使用、链式调用以及静态方法。同时,我们还手动实现了一个简化版的 Promise,深入理解了 Promise 的核心机制,包括状态管理、回调队列、链式调用以及静态方法。虽然这个实现未完全符合 Promises/A+ 规范,但它足以帮助我们理解 Promise 的工作原理。

在实际开发中,建议使用原生 Promise,因为它经过了严格测试和优化。但通过手动实现,我们可以更好地掌握异步编程的本质,写出更优雅、更易维护的代码。

希望这篇文章对你有所帮助!如果你有任何问题或建议,欢迎留言讨论。

你可能感兴趣的:(JavaScript,javascript,ajax,开发语言)