前端开发,Promise 从原理到实现,一文通

前言

Promisejs 异步编程的核心概念之一,它为我们提供了一种更优雅的方式来处理异步操作。

本文将全面剖析 Promise 的工作原理,并逐步实现一个符合 Promise/A+ 规范的 Promise 库

正文

一、Promise 基础概念

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

  1. pending初始状态,既不是成功,也不是失败状态
  2. fulfilled :意味着操作成功完成
  3. rejected :意味着操作失败

状态一旦改变就不能再变,只能从 pending 变为 fulfilled ,或从 pending 变为 rejected

二、Promise 核心静态方法实现

1. Promise.resolve 实现

Promise.resolve 方法返回一个以给定值解析后的 Promise 对象

javascript 复制代码
Promise.resolve = (param) => {
  if(param instanceof Promise) return param;
  return new Promise((resolve, reject) => {
    if(param && param.then && typeof param.then === 'function') {
      // param 状态变为成功会调用resolve,将新 Promise 的状态变为成功,反之亦然
      param.then(resolve, reject);
    }else {
      resolve(param);
    }
  })
}

实现要点:

  • 如果参数Promise 实例,直接返回该实例
  • 如果参数是 thenable 对象(具有 then 方法的对象),返回的 Promise 会跟随这个对象`
  • 其他情况返回一个以该值为成功状态的 Promise 对象

2. Promise.reject 实现

Promise.reject 方法返回一个带有拒绝原因Promise 对象

javascript 复制代码
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason);
    });
}

与 resolve 不同,reject 会原封不动地将 reason 向下传递

三、Promise 实例方法实现

1. Promise.prototype.finally 实现

finally 方法无论 Promise 最终状态如何都会执行。

javascript 复制代码
Promise.prototype.finally = function(callback) {
  this.then(value => {
    return Promise.resolve(callback()).then(() => {
      return value;
    })
  }, error => {
    return Promise.resolve(callback()).then(() => {
      throw error;
    })
  })
}

实现要点:

  • 无论成功或失败都会执行回调
  • 保持原 Promise下传
  • 回调函数返回的 Promise 会等待执行完毕

2. Promise.prototype.then 实现

then 方法是 Promise 的核心,它返回一个新的 Promise

javascript 复制代码
MyPromise.prototype.then = function (onResolved, onRejected) {
  var self = this;
  var promise2;
  
  // onResolved 和 onRejected 都是可选的
  onResolved = typeof onResolved === 'function' ? onResolved : v => v;
  onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r };

  if (self.currentState === RESOLVED) {
    return (promise2 = new MyPromise(function (resolve, reject) {
      setTimeout(function () {
        try {
          var x = onResolved(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } catch (reason) {
          reject(reason);
        }
      });
    }));
  }
  
  // 其他状态类似处理...
}

四、Promise 高级静态方法实现

1. Promise.all 实现

Promise.all 接收一个 Promise 数组,当所有 Promise 都成功时返回结果数组,有一个失败则立即失败

javascript 复制代码
Promise.all = function(promises) {
  return new Promise((resolve, reject) => {
    let result = [];
    let index = 0;
    let len = promises.length;
    if(len === 0) {
      resolve(result);
      return;
    }

    for(let i = 0; i < len; i++) {
      Promise.resolve(promises[i]).then(data => {
        result[i] = data;
        index++;
        if(index === len) resolve(result);
      }).catch(err => {
        reject(err);
      })
    }
  })
}

2. Promise.race 实现

Promise.race 返回第一个完成的 Promise 的结果。

javascript 复制代码
Promise.race = function(promises) {
  return new Promise((resolve, reject) => {
    let len = promises.length;
    if(len === 0) return;
    for(let i = 0; i < len; i++) {
      Promise.resolve(promises[i]).then(data => {
        resolve(data);
        return;
      }).catch(err => {
        reject(err);
        return;
      })
    }
  })
}

3. Promise.allSettled 实现

Promise.allSettled 等待所有 Promise 完成无论成功或失败

javascript 复制代码
function allSettled(iterable) {
  return new Promise((resolve, reject) => {
    function addElementToResult(i, elem) {
      result[i] = elem;
      elementCount++;
      if (elementCount === result.length) {
        resolve(result);
      }
    }

    let index = 0;
    for (const promise of iterable) {
      const currentIndex = index;
      promise.then(
        (value) => addElementToResult(
          currentIndex, {
            status: 'fulfilled',
            value
          }),
        (reason) => addElementToResult(
          currentIndex, {
            status: 'rejected',
            reason
          }));
      index++;
    }
    if (index === 0) {
      resolve([]);
      return;
    }
    let elementCount = 0;
    const result = new Array(index);
  });
}

代码:完整 Promise 实现

下面是一个符合 Promise/A+ 规范的完整实现:

javascript 复制代码
// 三种状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";

function MyPromise(fn) {
  let _this = this;
  _this.currentState = PENDING;
  _this.value = undefined;
  _this.resolvedCallbacks = [];
  _this.rejectedCallbacks = [];

  _this.resolve = function (value) {
    if (value instanceof MyPromise) {
      return value.then(_this.resolve, _this.reject)
    }
    setTimeout(() => {
      if (_this.currentState === PENDING) {
        _this.currentState = RESOLVED;
        _this.value = value;
        _this.resolvedCallbacks.forEach(cb => cb());
      }
    })
  };

  _this.reject = function (reason) {
    setTimeout(() => {
      if (_this.currentState === PENDING) {
        _this.currentState = REJECTED;
        _this.value = reason;
        _this.rejectedCallbacks.forEach(cb => cb());
      }
    })
  }
  
  try {
    fn(_this.resolve, _this.reject);
  } catch (e) {
    _this.reject(e);
  }
}

// then 方法实现
MyPromise.prototype.then = function (onResolved, onRejected) {
  var self = this;
  var promise2;
  
  onResolved = typeof onResolved === 'function' ? onResolved : v => v;
  onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r };

  if (self.currentState === RESOLVED) {
    return (promise2 = new MyPromise(function (resolve, reject) {
      setTimeout(function () {
        try {
          var x = onResolved(self.value);
          resolutionProcedure(promise2, x, resolve, reject);
        } catch (reason) {
          reject(reason);
        }
      });
    }));
  }
  
  // 其他状态处理...
};

// 解析过程
function resolutionProcedure(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("Error"));
  }
  
  if (x instanceof MyPromise) {
    if (x.currentState === PENDING) {
      x.then(function (value) {
        resolutionProcedure(promise2, value, resolve, reject);
      }, reject);
    } else {
      x.then(resolve, reject);
    }
    return;
  }
  
  let called = false;
  if (x !== null && (typeof x === "object" || typeof x === "function")) {
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolutionProcedure(promise2, y, resolve, reject);
          },
          e => {
            if (called) return;
            called = true;
            reject(e);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
  1. 状态管理:Promise 的状态一旦改变就不能再变
  2. 异步执行:then 方法的回调需要异步执行
  3. 链式调用:then 方法必须返回一个新的 Promise
  4. 值穿透:then 的参数如果不是函数需要忽略
  5. Promise 解析过程:处理 thenable 对象和循环引用

总结

Promise 的核心在于状态管理链式调用异步处理

了解其底层原理,将使我们能够更好地使用和调试Promise代码,去运用一些第三方Promise库。

相关推荐
Lsx_5 分钟前
MultiRepo 和 Monorepo:代码管理的演进与选择
前端·javascript·架构
潘多编程16 分钟前
构建企业级Web应用:AWS全栈架构深度解析
前端·架构·aws
裕波19 分钟前
Vue 与 Vite 生态最新进展:迈向一体化与智能化的未来
前端·vue.js
destinying36 分钟前
当部分请求失败时,前端如何保证用户体验不崩溃?
前端·javascript·程序员
幼儿园技术家42 分钟前
Diff算法的简单介绍
前端
陈随易43 分钟前
为VSCode扩展开发量身打造的UI库 - vscode-elements
前端·后端·程序员
叁金Coder1 小时前
业务系统跳转Nacos免登录方案实践
前端·javascript·nginx·nacos
蓝倾1 小时前
京东商品销量数据如何获取?API接口调用操作详解
前端·api·fastapi
stoneship1 小时前
满帮微前端
前端
GKDf1sh1 小时前
【前端安全】聊聊 HTML 闭合优先级和浏览器解析顺序
前端·安全·html