本文介绍参考[PromiseA+]规范来实现一个符合规范的Promise库。

上面是ES6+实现的Promise核心方法,其整体结构也可以通过下面的打印查看

  /* 01-打印Promise类的内容(静态方法) */
console.dir(Promise) /* 打印输出(已经省略部分内容) */
// length: 1 期望形参数量((resolve,reject)=>{})
// name: "Promise" 类(构造函数)的名字
// prototype: Promise 原型对象
// then: ƒ then() then处理函数
// catch: ƒ catch() catch处理函数
// finally: ƒ finally() 完成的处理函数
// constructor: ƒ Promise() 原型的构造器属性
// race: ƒ race() 异步任务并发先执行完
// reject: ƒ reject() 包装为reject
// resolve: ƒ resolve() 包装为resolve
// all: ƒ all() 异步任务并发都执行完
// allSettled: ƒ allSettled()
// Symbol(Symbol.species): (...)
// Symbol(Symbol.toStringTag): "Promise"

Promises/A+ 规范约定的Promise的实现逻辑和核心代码。

/* 核心注解 */
/* 1、Promise应该被设计为一个类(构造函数) */
/* 2、Promise存在三种状态,分别是pending(等待)、rejected(失败) 和 resolved(成功)。*/
/* 3、Promise类(构造函数)接收一个“拥有两个函数参数的函数”作为参数,我们可以称之为执行器函数(executor)立即执行。*/
/* 4、Promise类(构造函数)内部应该以私有函数的方式来是实现reject和resolve函数。 */
/* 5、Promise内部考虑到异步任务的执行(譬如定时器)Promise状态无法立即完成等待->成功|失败的切换,使用注册/订阅模式*/
/* 6、Promise的then方法处理失败、成功、等待态(如果存在异步任务)的Promise后续任务。 */
/* 7、Promise的then方法应该实现链式调用,实现的策略是总是返回一个新的Promise对象 */ const PENDING = "PENDING";
const RESOLVED = "RESOLVED";
const REJECTED = "REJECTED"; function resolvePromise(promise, x, resolve, reject) { /* 1、死循环处理 */
if (promise === x) {
reject(new TypeError("# Chaining cycle detected for promise #<Promise>"))
} let called = false;
/* 2、区分返回值是基本值和(Promise)的情况*/
if ((typeof x === "object" && x != null) || typeof x === "function") {
try {
let then = x.then;
if (typeof then === "function") {
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise, 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);
}
} class Promise {
constructor(executor) {
this.status = PENDING;
this.value = this.reason = undefined;
this.rejectedCallBacks = [];
this.resolvedCallBacks = []; /* reject 和 resolve 应该被实现为私有函数 */
let resolve = (val) => { if (val instanceof Promise) {
return val.then(resolve, reject);
} if (this.status === PENDING) {
this.status = RESOLVED;
this.value = val;
this.resolvedCallBacks.forEach(fn => fn());
}
} let reject = (val) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = val;
this.rejectedCallBacks.forEach(fn => fn());
}
} /* 执行器函数应该立即执行,并进行异常处理 */
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
onRejected = typeof onRejected === "function" ? onRejected : e => { throw e } let promise = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0); } if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} if (this.status === PENDING) {
this.rejectedCallBacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}) this.resolvedCallBacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
})
return promise;
}
} /* 基准测试 */
Promise.defer = Promise.deferred = function() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
} module.exports = Promise;

规范基准测试

npm install promises-aplus-tests g
cd dist
promises-aplus-tests Promise.js

Promise还有一些诸如catch和resolve等方法,下面简单给出它们的实现代码。

class Promise{
/* .... */
catch (errCallBack) {
return this.then(null, errCallBack); /* 为了支持链式调用,此处需要return */
}
static resolve(data) {
return new Promise((resolve, reject) => {
resolve(data)
})
}
static reject(err) {
return new Promise((resolve, reject) => {
reject(err);
})
}
finally(callBack) {
return this.then((value) => {
return Promise.resolve(callBack()).then(() => value);
}, reason => {
return Promise.resolve(callBack()).then(() => { throw reason });
})
}
}

前端开发系列131-进阶篇之Promise源码实现的更多相关文章

  1. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  2. leaflet-webpack 入门开发系列一初探篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  3. openlayers4 入门开发系列之热力图篇(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  4. chromium浏览器开发系列第三篇:chromium源码目录结构

    上两篇介绍了下载源码和编译源码,这次主要介绍chromium的源码目录结构,我也是通过源码和官网结合来跟大家说,如果有说的不准确的,欢迎交流. 另外,官网的不一定准确,他们其实也很懒,所以最主要还是靠 ...

  5. cesium-webpack 入门开发系列一初探篇(附源码下载)

    前言 cesium-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 we ...

  6. openlayers5-webpack 入门开发系列结合 echarts4 实现散点图(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  7. 《Vue.js 3.x高效前端开发(视频教学版)》源码课件同步教学视频免费下载

    <Vue.js 3.x高效前端开发(视频教学版)>源码课件同步教学视频免费下载.获得出版社和作者授权,可用于个人学习使用,禁止任何形式的商用.

  8. openlayers4 入门开发系列之图层控制(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  9. openlayers4 入门开发系列结合 echarts4 实现统计图(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  10. [AngularJS] AngularJS系列(7) 进阶篇之promise

    目录 使用promise 补充说明 $q.all $q.when 在上节中,我们在http中使用了then 和 在ngResource中返回了一个'延迟对象'. 本节介绍一下angular中的prom ...

随机推荐

  1. 使用XML的方式编写:@Aspect运用

    例子. 接口 public interface Calculator { // 加 public int add(int i, int j); // 减 public int sub(int i, i ...

  2. JAVA基础之多线程一期

    一.并发与并行的区别 并发:指同一时间段,两个或多个事件交替进行 并行:指同一时间段,两个或多个事件同时进行 二.进程与线程的区别 进程:正在内存中运行的程序就是进程 线程:线程归属于进程,它是进程中 ...

  3. javaweb基础之HTTP、Request、Response、ServletContext

    一.http协议是一个重要的协议,他是贯穿整合B/S架构的核心协议.因此学习http协议的时候一定要从请求和响应两个角度思考.注意方向性(请求:浏览器->服务器:响应:服务器->浏览器) ...

  4. FastAPI与SQLAlchemy数据库集成与CRUD操作

    title: FastAPI与SQLAlchemy数据库集成与CRUD操作 date: 2025/04/16 09:50:57 updated: 2025/04/16 09:50:57 author: ...

  5. python多个数列(列表)合并,合并后取值的方法

    有时候需要从一个excel或者多个excel读取多列数据,然后传到后面的步骤内去执行操作 这里就涉及到把数据合并再分割的问题,比如下图excel数据,取出两列手机号和余额 思路,先从目标excel内逐 ...

  6. 康谋技术 |高效同步与处理:ADTF流服务在自动驾驶数采中的应用

    随着自动驾驶技术的发展,车辆的智能化程度不断提高,这体现了车辆感知,决策以及执行的能力.在算法开发和迭代过程中,提高测试和开发效率,关键在于多传感器数据的高质量采集,确保数据的同步性.完整性和一致性. ...

  7. GC垃圾收集时,居然还有用户线程在奔跑

    之前面试被问到过"当GC垃圾收集时,是所有的用户线程都停止了吗?",这一篇我们来探究一下这个问题. 其实执行本地代码的线程仍然可以运行,那么这些线程一旦改变了对象中的引用关系或创建 ...

  8. 在 Spring Boot 2 中集成 JCasbin 并实现 ClassPath 模型文件加载

    在 Spring Boot 2 中集成 JCasbin 并实现 ClassPath 模型文件加载 概述 在现代Web应用开发中,权限管理和认证是不可或缺的一部分.JCasbin 是一个强大的.高效的开 ...

  9. 仿EXCEL插件,智表ZCELL产品V2.2 版本发布,增加获取单元格类型、样式功能,优化键盘事件、数值千分位等功能

    详细请移步 智表(ZCELL)官网www.zcell.net 更新说明  这次更新主要应用户要求,增加获取单元格类型.样式功能,优化键盘事件.数值千分位等功能 ,欢迎大家体验使用. 本次版本更新内容如 ...

  10. vue3 学习-初识体验-组件 component

    组件可以简单理解为 "页面构成的一部分". 组件化是 Vue 最为重要的设计理念之一吧. 早期的前端页面基本上就拆分为一个个的html, css, js 文件, 然后不断" ...