您现在的位置是:网站首页 > 手写Promise面试题文章详情

手写Promise面试题

陈川 JavaScript 8608人已围观

在JavaScript中,Promise是一个用于异步编程的对象,代表了未来可能完成或失败的操作的结果。它可以处于三种状态之一:pending(等待中)、fulfilled(已完成)或rejected(已拒绝)。一旦Promise被解决(无论是完成还是拒绝),它将保持在该状态,不会再改变。

Promise的基本使用

在标准JavaScript中,创建一个Promise对象通常如下所示:

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const result = '异步操作成功';
    resolve(result); // 成功时调用resolve
  }, 1000);
});

我们可以使用.then().catch()方法来处理Promise的成功和失败情况:

promise
  .then(result => {
    console.log('成功结果:', result);
  })
  .catch(error => {
    console.error('错误信息:', error);
  });

手写Promise

接下来,我们将从零开始构建一个简单的Promise实现。首先定义一个MyPromise构造函数,它接受一个执行器作为参数,这个执行器接收resolvereject两个函数作为参数:

function MyPromise(executor) {
  let state = 'pending';
  let value = null;
  let reason = null;
  let onFulfilledCallbacks = [];
  let onRejectedCallbacks = [];

  function resolve(val) {
    if (state === 'pending') {
      state = 'fulfilled';
      value = val;
      onFulfilledCallbacks.forEach(fn => fn());
    }
  }

  function reject(err) {
    if (state === 'pending') {
      state = 'rejected';
      reason = err;
      onRejectedCallbacks.forEach(fn => fn());
    }
  }

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

为了使我们的MyPromise可以链式调用,我们需要实现then方法:

MyPromise.prototype.then = function(onFulfilled, onRejected) {
  onFulfilled =
    typeof onFulfilled === 'function' ? onFulfilled : value => value;
  onRejected =
    typeof onRejected === 'function'
      ? onRejected
      : reason => { throw reason; };

  let promise2 = new MyPromise((resolve, reject) => {
    if (this.state === 'fulfilled') {
      setTimeout(() => {
        try {
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    } else if (this.state === 'rejected') {
      setTimeout(() => {
        try {
          let x = onRejected(this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    } else {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });

      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
    }
  });

  return promise2;
};

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  let called;

  if ((x instanceof MyPromise)) {
    if (x.state === 'pending') {
      x.then(y => resolvePromise(promise2, y, resolve, reject), reject);
    } else {
      x.then(resolve, reject);
    }
  } else if (x && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

在这个实现中,我们还添加了对Promise.all的支持,以便能够同时处理多个Promise

MyPromise.all = function(promises) {
  return new MyPromise((resolve, reject) => {
    let results = [];
    let count = 0;

    promises.forEach((promise, index) => {
      promise.then(value => {
        results[index] = value;
        count++;

        if (count === promises.length) {
          resolve(results);
        }
      }, reject);
    });
  });
};

结论

通过手动实现Promise,我们不仅加深了对异步编程的理解,还掌握了Promise的工作原理和内部结构。虽然我们的MyPromise实现较为基础,但它涵盖了Promise的核心功能,包括状态管理、异步操作的处理以及链式调用。在实际项目中,你可能不会需要自己实现Promise,但在理解其底层逻辑后,你将能够更加自信地使用原生PromiseAPI,从而编写出更高效、更可维护的代码。

我的名片

网名:川

职业:前端开发工程师

现居:四川省-成都市

邮箱:chuan@chenchuan.com

站点信息

  • 建站时间:2017-10-06
  • 网站程序:Koa+Vue
  • 本站运行
  • 文章数量
  • 总访问量
  • 微信公众号:扫描二维码,关注我
微信公众号
每次关注
都是向财富自由迈进的一步