Promises/A+知识及其实现过程

promise 核心要点#

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

  • 待定 (pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已成功 (fulfilled): 意味着操作成功完成。
  • 已拒绝 (rejected): 意味着操作失败。

当 promise 被调用后,它会以处理中状态 (pending) 开始。 这意味着调用的函数会继续执行,而 promise 仍处于处理中直到解决为止,从而为调用的函数提供所请求的任何数据。

被创建的 promise 最终会以被解决状态 (fulfilled)被拒绝状态 (rejected) 结束,并在完成时调用相应的回调函数(传给 thencatch)。

Copy
class myPromise { // 用static创建静态属性,用来管理状态 static PENDING = 'pending'; static FULFILLED = 'fulfilled'; static REJECTED = 'rejected'; // 构造函数:通过new命令生成对象实例时,自动调用类的构造函数 constructor(func) { // 给类的构造方法constructor添加一个参数func this.PromiseState = myPromise.PENDING; // 指定Promise对象的状态属性 PromiseState,初始值为pending this.PromiseResult = null; // 指定Promise对象的结果 PromiseResult this.onFulfilledCallbacks = []; // 保存成功回调 this.onRejectedCallbacks = []; // 保存失败回调 try { /** * func()传入resolve和reject, * resolve()和reject()方法在外部调用,这里需要用bind修正一下this指向 * new 对象实例时,自动执行func() */ func(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { // 生成实例时(执行resolve和reject),如果报错,就把错误信息传入给reject()方法,并且直接执行reject()方法 this.reject(error) } } resolve(result) { // result为成功态时接收的终值 // 只能由pending状态 => fulfilled状态 (避免调用多次resolve reject) if (this.PromiseState === myPromise.PENDING) { this.PromiseState = myPromise.FULFILLED; this.PromiseResult = result; /** * 在执行resolve或者reject的时候,遍历自身的callbacks数组, * 看看数组里面有没有then那边 保留 过来的 待执行函数, * 然后逐个执行数组里面的函数,执行的时候会传入相应的参数 */ this.onFulfilledCallbacks.forEach(callback => { callback(result) }) } } reject(reason) { // reason为拒绝态时接收的终值 // 只能由pending状态 => rejected状态 (避免调用多次resolve reject) if (this.PromiseState === myPromise.PENDING) { this.PromiseState = myPromise.REJECTED; this.PromiseResult = reason; this.onRejectedCallbacks.forEach(callback => { callback(reason) }) } } /** * [注册fulfilled状态/rejected状态对应的回调函数] * @param {function} onFulfilled fulfilled状态时 执行的函数 * @param {function} onRejected rejected状态时 执行的函数 * @returns {function} newPromsie 返回一个新的promise对象 */ then(onFulfilled, onRejected) { // 2.2.7规范 then 方法必须返回一个 promise 对象 let promise2 = new myPromise((resolve, reject) => { if (this.PromiseState === myPromise.FULFILLED) { /** * 为什么这里要加定时器setTimeout? * 2.2.4规范 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用 注1 * 这里的平台代码指的是引擎、环境以及 promise 的实施代码。 * 实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。 * 这个事件队列可以采用“宏任务(macro-task)”机制,比如setTimeout 或者 setImmediate; 也可以采用“微任务(micro-task)”机制来实现, 比如 MutationObserver 或者process.nextTick。 */ setTimeout(() => { try { if (typeof onFulfilled !== 'function') { // 2.2.7.3规范 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值 resolve(this.PromiseResult); } else { // 2.2.7.1规范 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x),即运行resolvePromise() let x = onFulfilled(this.PromiseResult); resolvePromise(promise2, x, resolve, reject); } } catch (e) { // 2.2.7.2规范 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e reject(e); // 捕获前面onFulfilled中抛出的异常 } }); } else if (this.PromiseState === myPromise.REJECTED) { setTimeout(() => { try { if (typeof onRejected !== 'function') { // 2.2.7.4规范 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因 reject(this.PromiseResult); } else { let x = onRejected(this.PromiseResult); resolvePromise(promise2, x, resolve, reject); } } catch (e) { reject(e) } }); } else if (this.PromiseState === myPromise.PENDING) { // pending 状态保存的 onFulfilled() 和 onRejected() 回调也要符合 2.2.7.1,2.2.7.2,2.2.7.3 和 2.2.7.4 规范 this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { if (typeof onFulfilled !== 'function') { resolve(this.PromiseResult); } else { let x = onFulfilled(this.PromiseResult); resolvePromise(promise2, x, resolve, reject); } } catch (e) { reject(e); } }); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { if (typeof onRejected !== 'function') { reject(this.PromiseResult); } else { let x = onRejected(this.PromiseResult); resolvePromise(promise2, x, resolve, reject); } } catch (e) { reject(e); } }); }); } }) return promise2 } } /** * 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理 * @param {promise} promise2 promise1.then方法返回的新的promise对象 * @param {[type]} x promise1中onFulfilled或onRejected的返回值 * @param {[type]} resolve promise2的resolve方法 * @param {[type]} reject promise2的reject方法 */ function resolvePromise(promise2, x, resolve, reject) { // 2.3.1规范 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise if (x === promise2) { throw new TypeError('Chaining cycle detected for promise'); } if (x instanceof myPromise) { /** * 2.3.2 如果 x 为 Promise ,则使 promise2 接受 x 的状态 * 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y */ x.then(y => { resolvePromise(promise2, y, resolve, reject) }, reject); } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) { // 2.3.3 如果 x 为对象或函数 try { // 2.3.3.1 把 x.then 赋值给 then var then = x.then; } catch (e) { // 2.3.3.2 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise return reject(e); } /** * 2.3.3.3 * 如果 then 是函数,将 x 作为函数的作用域 this 调用之。 * 传递两个回调函数作为参数, * 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise` */ if (typeof then === 'function') { // 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 let called = false; // 避免多次调用 try { then.call( x, // 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y) y => { if (called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, // 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise r => { if (called) return; called = true; reject(r); } ) } catch (e) { /** * 2.3.3.3.4 如果调用 then 方法抛出了异常 e * 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之 */ if (called) return; called = true; // 2.3.3.3.4.2 否则以 e 为据因拒绝 promise reject(e); } } else { // 2.3.3.4 如果 then 不是函数,以 x 为参数执行 promise resolve(x); } } else { // 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise return resolve(x); } }

Promise A+ 测试#

1. 安装官方测试工具#

我们使用Promises/A+官方的测试工具 promises-aplus-tests 来对我们的myPromise进行测试

安装 promises-aplus-tests:

Copy
npm install promises-aplus-tests -D 复制代码

安装完测试工具后的项目目录:

在这里插入图片描述

2. 使用 CommonJS 对外暴露 myPromise 类#

Copy
class myPromise { ... } function resolvePromise(promise2, x, resolve, reject) { ... } + module.exports = myPromise; 复制代码

3. 实现静态方法 deferred#

要使用 promises-aplus-tests 这个工具测试,必须实现一个静态方法deferred(),官方对这个方法的定义如下:

在这里插入图片描述

意思就是:

我们要给自己手写的myPromise上实现一个静态方法deferred(),该方法要返回一个包含{ promise, resolve, reject }的对象:

  • promise 是一个处于pending状态的 Promsie。
  • resolve(value)value解决上面那个promise
  • reject(reason)reason拒绝上面那个promise

deferred()的实现如下:

Copy
class myPromise { ... } function resolvePromise(promise2, x, resolve, reject) { ... } + myPromise.deferred = function () { + let result = {}; + result.promise = new myPromise((resolve, reject) => { + result.resolve = resolve; + result.reject = reject; + }); + return result; + } module.exports = myPromise; 复制代码

4. 配置 package.json#

我们实现了deferred 方法,也通过 CommonJS 对外暴露了myPromise,最后配置一下package.json就可以跑测试啦~😺

新建一个 package.json配置如下:

Copy
// package.json { "devDependencies": { "promises-aplus-tests": "^2.1.2" }, "scripts": { "test": "promises-aplus-tests myPromise" } } 复制代码

项目目录:

在这里插入图片描述

执行测试命令:

Copy
npm run test

肯定都等不及了吧~😜 快来看看我们的测试结果吧,走起 🚀

在这里插入图片描述

Promises/A+ 测试总共872用例,我们写的Promise完美通过了所有用例:

在这里插入图片描述

参考链接

作者:圆圆01
链接:https://juejin.cn/post/7043758954496655397
来源:稀土掘金

posted @   Scok  阅读(133)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS