返回

用最少的代码手工实现一个Promise,5分钟看懂

前端

**## **

**## **

序言

在现代软件开发中,异步编程已经成为一种不可或缺的技术。它允许程序在不阻塞主线程的情况下执行耗时的操作,从而提高程序的响应速度和并发能力。而Promise,作为一种异步编程的利器,在JavaScript中扮演着至关重要的角色。它不仅可以简化异步编程的代码结构,还可以让代码更加清晰易读。

Promise的原理与实现

1. Promise的构造函数

Promise是一个构造函数,它接受一个执行器函数作为参数。执行器函数有两个参数,分别是resolve和reject。resolve用于将Promise的状态从pending变为fulfilled,并携带一个值作为结果;reject用于将Promise的状态从pending变为rejected,并携带一个值作为错误原因。

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

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

2. Promise的状态

Promise的状态可以分为三种:pending、fulfilled和rejected。

  • pending:表示Promise尚未完成,处于等待状态。
  • fulfilled:表示Promise已完成,并且成功执行。
  • rejected:表示Promise已完成,但执行过程中发生了错误。

3. Promise的方法

Promise提供了几个有用的方法,包括:

  • then:用于注册回调函数,当Promise的状态改变时,回调函数将被调用。
  • catch:用于注册错误处理函数,当Promise的状态变为rejected时,错误处理函数将被调用。
  • finally:用于注册一个回调函数,无论Promise的状态如何,该回调函数都会被调用。

4. Promise的链式调用

Promise支持链式调用,这使得代码更加简洁和易读。链式调用是通过then方法实现的。then方法返回一个新的Promise,这个新的Promise的状态取决于前一个Promise的状态。如果前一个Promise的状态是fulfilled,则新Promise的状态也是fulfilled,并且新Promise的值是前一个Promise的值。如果前一个Promise的状态是rejected,则新Promise的状态也是rejected,并且新Promise的错误原因是前一个Promise的错误原因。

promise1
  .then(function(value) {
    return value + 1;
  })
  .then(function(value) {
    console.log(value); // 输出 2
  });

手工实现一个Promise

手工实现一个Promise并不困难,只需要几个简单的步骤。

1. 创建Promise构造函数

首先,我们需要创建一个Promise构造函数。这个构造函数接受一个执行器函数作为参数。执行器函数有两个参数,分别是resolve和reject。resolve用于将Promise的状态从pending变为fulfilled,并携带一个值作为结果;reject用于将Promise的状态从pending变为rejected,并携带一个值作为错误原因。

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

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

2. 实现Promise的方法

接下来,我们需要实现Promise的方法,包括then、catch和finally。

  • then方法:then方法接受两个参数,分别是fulfilledCallback和rejectedCallback。当Promise的状态改变时,fulfilledCallback或rejectedCallback将被调用。
Promise.prototype.then = function(fulfilledCallback, rejectedCallback) {
  if (typeof fulfilledCallback !== 'function') {
    fulfilledCallback = function(value) {
      return value;
    };
  }

  if (typeof rejectedCallback !== 'function') {
    rejectedCallback = function(reason) {
      throw reason;
    };
  }

  var newPromise = new Promise(function() {});

  this.onFulfilledCallbacks.push(function() {
    var value = fulfilledCallback(this.value);
    resolve(newPromise, value);
  });

  this.onRejectedCallbacks.push(function() {
    var reason = rejectedCallback(this.reason);
    reject(newPromise, reason);
  });

  return newPromise;
};
  • catch方法:catch方法接受一个参数,是一个错误处理函数。当Promise的状态变为rejected时,错误处理函数将被调用。
Promise.prototype.catch = function(rejectedCallback) {
  return this.then(undefined, rejectedCallback);
};
  • finally方法:finally方法接受一个参数,是一个回调函数。无论Promise的状态如何,该回调函数都会被调用。
Promise.prototype.finally = function(callback) {
  return this.then(
    function() {
      callback();
    },
    function() {
      callback();
    }
  );
};

3. 实现resolve和reject函数

最后,我们需要实现resolve和reject函数。resolve函数用于将Promise的状态从pending变为fulfilled,并携带一个值作为结果;reject函数用于将Promise的状态从pending变为rejected,并携带一个值作为错误原因。

function resolve(promise, value) {
  if (promise.state !== 'pending') {
    return;
  }

  promise.state = 'fulfilled';
  promise.value = value;

  for (var i = 0; i < promise.onFulfilledCallbacks.length; i++) {
    promise.onFulfilledCallbacks[i]();
  }
}

function reject(promise, reason) {
  if (promise.state !== 'pending') {
    return;
  }

  promise.state = 'rejected';
  promise.reason = reason;

  for (var i = 0; i < promise.onRejectedCallbacks.length; i++) {
    promise.onRejectedCallbacks[i]();
  }
}

结语

以上就是手工实现一个Promise的全部过程。通过这个过程,我们对Promise的原理和实现有了更深入的理解。掌握了Promise的原理和实现,我们就可以在实际项目中熟练地使用Promise,从而编写出更加优雅和易维护的异步代码。