本文介绍参考[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. jmeter使用之数据关联

  2. 1、HTML常用标签

    此文章为学习笔记以下内容为HTML常用标签. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset=&quo ...

  3. 腾讯云短信发送【java】

    先去官网申请secretId, secretKey,然后创建对应的模板 maven引入包 <dependency> <groupId>com.tencentcloudapi&l ...

  4. ArcGIS Desktop 10.7 完美汉化安装教程

    1,下载文件并解压缩,双击[Esri ArcGIS Desktop v10.7.0.exe] 2.在安装向导中选择[Next] 3.选中[I accept the master agreement]我 ...

  5. Mybatis 框架课程第一天

    目录 1 框架概述 1.1 MyBatis 框架概述 1.2 JDBC 编程的分析 1.2.1 jdbc 程序的回顾 1.2.2 jdbc问题分析 2 Mybatis框架快速入门 2.1 Mybati ...

  6. 基于docker的AI-Codereview-Gitlab部署实战

    AI-Codereview-Gitlab是一个基于大模型的自动化代码审查工具,帮助开发团队在代码合并或提交时,快速进行智能化的审查(Code Review),提升代码质量和开发效率. 主要功能 多模型 ...

  7. 仿EXCEL插件,智表ZCELL产品V2.1 版本发布,增加列标、行标自定义设置及单元格属性自定义相关功能,优化公式随动功能

    详细请移步 智表(ZCELL)官网www.zcell.net 更新说明  这次更新主要应用户要求,增加列标.行标自定义设置及单元格属性自定义相关功能,优化公式随动功能 ,欢迎大家体验使用. 本次版本更 ...

  8. JS 构造函数与类

    严格来说, JS 并不是一个面向对象的语言, 类似 Java, Python, C++ 这样的. JS 的独特精妙的设计其实是 原型 prototype 因此这里讲一嘴面向对象其实是为了后面引出原型的 ...

  9. 凯亚物联网增加MQTT设备功能测试

    一.前言 这几天一直在测试设备功能,并且搭建了线上流媒体推送,内存还比较稳定,.NET 8.0 性能不错,内存控制已经赶上了C++了,大家闲暇时间可以玩玩设备功能以及其它功能,过几天会发布测试版提供下 ...

  10. Django踩坑之django.core.exceptions.ImproperlyConfigured mysqlclient 1.3.13 or newer is required; you have 0.9.3.

    安装Django3后不想折腾mysqlclient那堆库文件,直接装了pymysql替代mysqlclient,报错:django.core.exceptions.ImproperlyConfigur ...