返回

Promise 从手写实现到基本应用

前端

Promise概述
Promise是JavaScript中用于异步编程的解决方案,它提供了一种管理异步操作的状态和结果的方法。Promise对象代表一个异步操作,它有三种状态:Pending(等待)、Fulfilled(已完成)和Rejected(已拒绝)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。一旦状态改变就不会再变,任何时候都可以通过then方法、catch方法和finally方法来获取异步操作的结果或处理错误。

手写实现Promise

为了更好地理解Promise的工作原理,我们首先从手写实现一个简单的Promise开始。

class Promise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled';
      this.value = value;
      this.onFulfilledCallbacks.forEach((callback) => callback(value));
    };

    const reject = (reason) => {
      if (this.state !== 'pending') return;
      this.state = 'rejected';
      this.reason = reason;
      this.onRejectedCallbacks.forEach((callback) => callback(reason));
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        this.onFulfilledCallbacks.push((value) => {
          setTimeout(() => {
            try {
              const result = onFulfilled(value);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push((reason) => {
          setTimeout(() => {
            try {
              const result = onRejected(reason);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
  }

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

  finally(onFinally) {
    return this.then(
      (value) => Promise.resolve(onFinally()).then(() => value),
      (reason) => Promise.resolve(onFinally()).then(() => { throw reason; })
    );
  }

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

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

Promise的基本用法

了解了Promise的基本原理后,我们来看看如何使用Promise。

回调函数

在使用Promise之前,我们通常使用回调函数来处理异步操作的结果。回调函数是一个在异步操作完成后被调用的函数,它可以获取异步操作的结果或错误信息。

function getData(callback) {
  setTimeout(() => {
    const data = 'Hello, world!';
    callback(data);
  }, 1000);
}

getData((data) => {
  console.log(data); // Hello, world!
});

then方法

Promise的then方法可以让我们在异步操作完成后执行特定的操作。then方法接收两个参数:onFulfilled和onRejected。onFulfilled是异步操作成功完成时执行的函数,onRejected是异步操作失败时执行的函数。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const data = 'Hello, world!';
    resolve(data);
  }, 1000);
});

promise.then((data) => {
  console.log(data); // Hello, world!
}, (reason) => {
  console.log(reason); // Error: Something went wrong!
});

catch方法

Promise的catch方法可以让我们在异步操作失败时执行特定的操作。catch方法接收一个参数:onRejected。onRejected是异步操作失败时执行的函数。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('Something went wrong!'));
  }, 1000);
});

promise.catch((reason) => {
  console.log(reason); // Error: Something went wrong!
});

finally方法

Promise的finally方法可以让我们在异步操作完成后无论成功还是失败都会执行特定的操作。finally方法接收一个参数:onFinally。onFinally是异步操作完成后执行的函数。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello, world!');
  }, 1000);
});

promise.finally(() => {
  console.log('This will always be executed.');
});

Promise.all

Promise.all方法可以让我们等待多个Promise同时完成,然后返回一个包含所有Promise结果的数组。

const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
];

Promise.all(promises).then((results) => {
  console.log(results); // [1, 2, 3]
});

Promise.race

Promise.race方法可以让我们等待多个Promise中第一个完成的Promise,然后返回该Promise的结果。

const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.reject(new Error('Something went wrong!'))
];

Promise.race(promises).then((result) => {
  console.log(result); // 1
}, (reason) => {
  console.log(reason); // Error: Something went wrong!
});

结语

Promise是JavaScript中用于异步编程的解决方案,它可以帮助我们轻松管理异步操作的状态和结果。Promise的基本用法包括回调函数、then方法、catch方法、finally方法、Promise.all和Promise.race等。通过熟练掌握Promise的用法,我们可以提升异步编程的能力,编写出更加健壮和可维护的代码。