返回

Promise学习笔记:用通俗易懂的语言,系统掌握异步编程

前端

异步编程:从阻塞到非阻塞

在传统的同步编程中,程序会逐行执行,直到完成整个操作才继续下一步。而异步编程则不同,它允许程序在等待耗时操作(如网络请求、文件读取等)完成的同时执行其他任务。

Promise:异步编程的利器

Promise是一种用于处理异步操作的 JavaScript 对象。它表示一个最终会完成或失败的异步操作。Promise 提供了统一的 API,简化了异步编程,让我们可以像处理同步操作一样处理异步操作。

Promise 的 API

Promise 的 API 非常简洁,只有三个方法:

  • then(onFulfilled, onRejected):在 Promise 完成或失败时执行指定的回调函数。
  • catch(onRejected):在 Promise 失败时执行指定的回调函数。
  • finally(onFinally):无论 Promise 完成还是失败,都会执行指定的回调函数。

异常穿透

如果在 Promise 的回调函数中抛出错误,可以通过 .catch() 方法捕获异常。如果未捕获异常,它将穿透到外部作用域,导致 JavaScript 引擎停止运行。

链式调用

Promise 的链式调用是一个非常强大的功能,它允许我们依次执行一系列异步操作。在每个 .then() 回调中,我们可以返回一个新的 Promise,该 Promise 会成为链中下一个操作的输入。

Async 和 Await

Async 和 Await 是 ES2017 引入的语法糖,它们可以简化异步编程。async 函数返回一个 Promise,await 表达式会暂停函数的执行,直到给定的 Promise 完成。

手写 Promise

为了更深入地理解 Promise,我们可以尝试自己手写一个 Promise。这有助于我们理解 Promise 的内部工作原理。

示例代码

// 手写 Promise
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.error = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    // 执行器函数
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // 成功状态改变
  resolve(value) {
    if (this.state !== 'pending') return;
    this.state = 'fulfilled';
    this.value = value;
    this.onFulfilledCallbacks.forEach(callback => callback(value));
  }

  // 失败状态改变
  reject(error) {
    if (this.state !== 'pending') return;
    this.state = 'rejected';
    this.error = error;
    this.onRejectedCallbacks.forEach(callback => callback(error));
  }

  // 添加成功回调
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') onFulfilled = value => value;
    if (typeof onRejected !== 'function') onRejected = error => { throw error; };
    const newPromise = new MyPromise(() => {});

    if (this.state === 'fulfilled') {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(newPromise, x);
        } catch (error) {
          rejectPromise(newPromise, error);
        }
      }, 0);
    } else if (this.state === 'rejected') {
      setTimeout(() => {
        try {
          const x = onRejected(this.error);
          resolvePromise(newPromise, x);
        } catch (error) {
          rejectPromise(newPromise, error);
        }
      }, 0);
    } else {
      this.onFulfilledCallbacks.push(onFulfilled);
      this.onRejectedCallbacks.push(onRejected);
    }

    return newPromise;
  }

  // 添加失败回调
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // 添加 finally 回调
  finally(onFinally) {
    this.then(
      () => onFinally(),
      () => onFinally()
    );
  }

  // 处理 Promise 的 resolve 和 reject
  static resolve(value) {
    return new MyPromise(resolve => resolve(value));
  }

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

  // Promise 的 all 方法
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const values = [];
      let resolvedCount = 0;
      promises.forEach((promise, index) => {
        promise.then(value => {
          values[index] = value;
          resolvedCount++;
          if (resolvedCount === promises.length) resolve(values);
        }).catch(error => reject(error));
      });
    });
  }

  // Promise 的 race 方法
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, reject);
      });
    });
  }
}

总结

Promise 是异步编程中的重要工具,它使我们能够优雅地处理异步操作。通过了解 Promise 的 API、异常穿透、链式调用以及手写 Promise,我们可以更深入地理解异步编程的原理。掌握 Promise 有助于我们编写出更健壮、更易于维护的 JavaScript 代码。