北京和隆优化科技,泰安seo排名,南京网站制作有限公司,南通网站关键词推广一直以来对Promise只是会用简单的方法#xff0c;例如then#xff0c;catch等#xff0c;对于其余各种方法也只是简单了解#xff0c;这次想要通过实现Promise来加深对Promise的使用 话不多说#xff0c;直接开始#xff0c;简单粗暴一步步来 一#xff1a;了解Promise … 一直以来对Promise只是会用简单的方法例如thencatch等对于其余各种方法也只是简单了解这次想要通过实现Promise来加深对Promise的使用 话不多说直接开始简单粗暴一步步来 一了解Promise 1.1 什么是Promise Promise是一种用于处理异步操作的JS对象可以通过链式调用的方式来处理操作的结果 使Promise可以更加优雅地处理异步代码避免回调地狱的产生 1.2 Promise的三种状态 Pending进行中初始状态表示操作尚未完成 Fulfilled已完成表示操作成功完成 Rejected已拒绝表示操作失败 1.3 示例 通过示例来了解Promise的基本用法 const p new Promise((resolve, reject) { resolve(1) }) const p2 p.then(res { console.log(res) // 1 throw xxx }) p2.catch(error { console.log(error); //xxx }) 通过 new Promise创建一个Promise实例对象在构造函数中传入一个执行器函数该函数接收两个参数 resolve函数如果操作成功调用resolve函数并传递结果 reject函数如果调用失败或抛出错误调用reject函数并传递错误信息 通过Promise的实例对象上的 then方法可以指定操作成功时所要执行的回调函数 通过 catch方法可以指定操作失败时候要执行的回调函数 在上述代码中调用resolve函数更改为成功状态并传递结果1 通过调用p实例上的then方法来接收传递的结果res接收到的结果即是1并自定义回调函数在回调函数中抛出错误信息xxx并使用p2来接收p.then的返回值 p2实际也是一个Promise实例因为promise支持链式调用返回值也是一个promise对象那么p.then中抛出的错误会被p2实例身上的catch方法捕获 最终通过 catch方法打印对应的错误信息 状态变化 执行器函数执行 resolve(1)会将p实例对象的状态由 Pending转为 Fulfilled状态即由待定状态转为成功状态 在p实例的then回调函数中抛出错误信息xxx由于异常未被捕获p2对象状态被设置为 Rejectedp2实例的catch方法会根据此时p2实例的状态捕获错误信息xxx then方法 实际上Promise对象的 then方法会根据实例的不同状态执行不同的处理方法 then方法接收两个可选参数 onFulfied和 onRejected分别表示成功时和失败时的回调函数 当Promise对象的状态为Fulfilled已完成时 then方法会立即执行 onFulfilled回调函数并将操作结果作为参数传递给该函数。 当Promise对象的状态为Rejected已拒绝时 then方法会立即执行 onRejected回调函数并将拒绝原因错误信息作为参数传递给该函数。 const p new Promise((resolve, reject) { resolve(1) // reject(xxx) }) p.then(res { console.log(res) // 1 }, error { console.log(error); }) 该代码如果执行resolve函数状态会被改为Fulfilled已完成那么就会执行then方法中的第一个回调函数并将1传递给res 如果执行reject函数状态会被改为Rejected已拒绝执行第二个回调函数并将xxx传递给error 在之前的代码中catch方法的功能和执行 onRejected回调函数第二个参数的回调函数是一致的都是用于当实例对象为 Rejected状态时候执行对应的回调函数并将错误信息作为参数传递给该函数 在MDN中有说明此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式 二实现Promise核心功能 了解Promise的基本使用过后那么就可以来一步步去实现一个Promise先去实现Promise的核心功能* 「构造函数」通过class创建 MyPromise类接收执行器函数resolve/reject并执行 「更改状态和原因」通过resolve和reject函数去更改实例对象的状态并将原因操作结果作为参数传递 「初步实现then方法」添加实例then方法并判断传入then方法的参数类型设置成功和失败的回调函数 「支持异步操作和多次调用」设置数组存储回调函数来实现多次通过实例调用then方法非链式调用通过设置异步函数来处理异步调用resolve/reject 「then的异步执行」 「then的链式调用」返回MyPromise实例异常处理获取then的返回值对于不同的返回值做出不同处理 2.1 构造函数 class MyPromise { // 1. 添加构造函数 constructor(func) { // 2. 定义resolve/reject const resolve (result) { console.log(result) //success } const reject (result) { console.log(result) } // 3. 执行回调函数 func(resolve, reject) } } const p new MyPromise((resolve, reject) { resolve(success) // reject(error) }) 创建构造函数并由 func接收传入的回调函数 设置回调函数的两个参数resolvereject函数 执行func回调函数 2.2 更改状态和设置原因 //1. 设置三种状态 const PENDING pending const FULFILLED fulfilled const REJECTED rejected class MyPromise { constructor(func) { //2. 设置result存储原因 /初始化状态 this.state PENDING this.result undefined const resolve (result) { //3. 通过resolve/reject修改状态 //注意判断状态条件 使得状态不可逆 if (this.state PENDING) { this.state FULFILLED this.result result } } const reject (result) { if (this.state PENDING) { this.state REJECTED this.result result } } func(resolve, reject) } } const p new MyPromise((resolve, reject) { resolve(success) reject(error) }) 设置三种状态pendingfufilledrejected。 初始化实例状态为pending 设置result变量存储resolve、reject传递过来的结果 执行resolve、reject函数时候修改状态 注意状态的不可逆状态只能由pending - fulfilled或者pending - rejected不可以从fulfilled - rejected条件判断一下 即便resolvereject都执行了实例状态还是由第一个执行的函数改变 const p new MyPromise((resolve, reject) { resolve(success) reject(error) }) image-20231010132809495 2.3 初步实现then方法 class MyPromise { constructor(func) { //... } // 1. 添加实例方法 then (onFulfilled, onRejected) { // 2. 参数判断 onFulfilled typeof onFulfilled function ? onFulfilled : x x onRejected typeof onRejected function ? onRejected : x { throw x } // 2.1 执行成功回调 // 2.2 执行失败回调 if (this.state FULFILLED) { onFulfilled(this.result) } else if (this.state REJECTED) { onRejected(this.result) } } } const p new MyPromise((resolve, reject) { resolve(success) // reject(error) }) p.then(res { console.log(p1:, res) // p1: success }) 添加实例then方法接收两个参数一个执行 成功的回调函数onFulfilled一个执行 失败的回调函数onRejected 作为调用者对then方法的参数可能设置有不同形式可能是简单的变量或是正确的回调函数形式因此在then方法内部需要对传递过来的参数进行一个判断 使用 typeof关键字对参数类型进行判断对于onFulfilled和onRejected如果是回调函数都不做处理 onFulfilled如果不是回调函数其内部转化为一个恒等函数(x) x只是简单的把值传递一下也没有什么处理 mdn上这么说如果 onFulfilled 不是一个函数则内部会被替换为一个 恒等函数 (x) x它只是简单地将兑现值向前传递。 onRejected如果不是回调函数对其抛出其拒绝的原因 mdn上这么说如果 onRejected 不是一个函数则内部会被替换为一个 抛出器函数 (x) { throw x; }它会抛出它收到的拒绝原因 关键在于状态判断根据实例的状态来执行不同的回调函数 FULFILLED状态执行第一个回调函数onFulfilled回调并把 原因结果传递给 then方法的 参数 REJECTED状态执行第二个回调函数onRejected回调并把 原因结果传递给 then方法的 参数 通过以上处理then方法就可以正确调用并可以根据不同状态执行不同的回调函数来接收对应的结果 2.4 支持异步操作和多次调用 此时then方法为同步 const p new MyPromise((resolve, reject) { resolve(success) }) p.then(res { console.log(p1:, res) //p1: success }) 根据目前我们实现的代码通过调用resolve函数改变实例状态通过then方法根据状态处理不同的结果成功打印success Promise是支持异步操作resolve/reject函数如果使用我们的代码直接设置异步操作能否正确输出结果呢 const p new MyPromise((resolve, reject) { setTimeout(() { resolve(success) }, 2000); }) p.then(res { console.log(p1:, res) }) image-20231010141014499 为什么无法正常输出呢设置一个定时器异步操作resolve为什么就无法在then方法中正确处理结果呢在控制台打印一下此时的实例状态 image-20231010141146295 很明显p的状态根据设置定时器初始为pending定时器结束后执行resolve设置为fulfilled状态那么想到此时的 then方法是同步的它不会等到定时器结束才执行 一开始实例状态是pending直接执行了then方法但我们没有在then方法中对pending状态做出处理也就没有正确执行回调所以就什么都没有了 那么怎么正确处理呢 先保存此时的回调和结果等状态改变了再执行 const PENDING pending const FULFILLED fulfilled const REJECTED rejected class MyPromise { constructor(func) { //... //保存成功的回调函数 this.onResolveCallbacks [] //保存失败的回调函数 this.onRejectCallbacks [] const resolve (result) { if (this.state PENDING) { this.state FULFILLED this.result result //遍历执行保存的回调函数 this.onResolveCallbacks.forEach(fn fn()) } } const reject (result) { if (this.state PENDING) { this.state REJECTED this.result result //遍历执行保存的回调函数 this.onRejectCallbacks.forEach(fn fn()) } } func(resolve, reject) } then (onFulfilled, onRejected) { //... if (this.state FULFILLED) { onFulfilled(this.result) } else if (this.state REJECTED) { onRejected(this.result) } else if (this.state PENDING) { //PENDING状态处理 this.onResolveCallbacks.push(() { onFulfilled(this.result) }) this.onRejectCallbacks.push(() { onRejected(this.result) }) } } } const p new MyPromise((resolve, reject) { setTimeout(() { resolve(success) }, 2000); }) p.then(res { console.log(p1:, res) //p1: success }) 添加两个数组用于存储执行成功和失败的回调函数在状态为pending的时候先添加到对应数组中 等待调用resolve/reject改变状态后再依次从数组中取出对应成功or失败的回调函数并执行 对于多次调用 then方法由于我们用数组存储回调函数即可以多次调用then方法了非链式调用 const p new MyPromise((resolve, reject) { setTimeout(() { resolve(success) }, 2000); }) p.then(res { console.log(p1:, res) }) p.then(res { console.log(p1:, res) }) p.then(res { console.log(p1:, res) }) 这次就成功打印结果了 image-20231010142108496 2.5 then的异步执行 在2.4中我们实现了异步操作resolve/reject能够成功处理对应结果但当时的then方法还是同步的 在Promise中 then方法是异步的 console.log(1); const p1 new Promise((resolve, reject) { resolve(success) }) p1.then(res { console.log(res); }) console.log(2); 执行结果为 1 2 success 在MyPromise中 我们未对then方法的调用处理异步此时还是同步的 console.log(1); const p new MyPromise((resolve, reject) { resolve(success) }) p.then(res { console.log(p1:, res) }) console.log(2); 执行结果为1 p1: success 2 使用settimeout处理异步 then (onFulfilled, onRejected) { //... if (this.state FULFILLED) { setTimeout(() { onFulfilled(this.result) }, 0); } else if (this.state REJECTED) { setTimeout(() { onRejected(this.result) }, 0); } else if (this.state PENDING) { //执行回调 this.onResolveCallbacks.push(() { setTimeout(() { onFulfilled(this.result) }, 0); }) this.onRejectCallbacks.push(() { setTimeout(() { onRejected(this.result) }, 0); }) } } } 通过 setTimeout 方法将 then 方法的执行放到宏任务中执行在同步任务执行完毕后then 方法才会被调用 2.6 then的链式调用 对于then的链式调用即需要实现很多关键点 返回一个新的MyPromise实例可以继续调用then方法 获取实例的返回值并处理异常 对于不同返回值做出不同的处理 普通返回值 返回值是MyPromise实例 返回值是对应的实例重复引用即该抛出错误 对于三种状态统一进行处理 返回一个新实例 then (onFulfilled, onRejected) { //... const p2 new MyPromise((resolve, reject) { //... }) return p2 } const p new MyPromise((resolve, reject) { resolve(success) }) p.then(res { console.log(p1:, res) return 1 }).then(res { console.log(p2:, res) }) image-20231010144315841 可以链式调用then方法不会报错但是第二个then方法明显无法第一个then方法的返回值说明未对第一个实例的返回值进行处理 在Promise中第一个then方法的返回值会传递给第二个链式调用的then方法的第一个回调函数的参数即第二个then应该打印p2: 1 获取实例的返回值并对异常做出处理 then (onFulfilled, onRejected) { //... const p2 new MyPromise((resolve, reject) { if (this.state FULFILLED) { setTimeout(() { try { const res onFulfilled(this.result) //将实例返回值传递给下一个then方法的onFulfilled回调函数 resolve(res) } catch (error) { //处理异常 将错误信息传递给下一个then方法的onRjected回调函数 reject(error) } }, 0); } //... return p2 } } const p new MyPromise((resolve, reject) { resolve(success) }) p.then(res { console.log(p1:, res) return 1 }).then(res { console.log(p2:, res) }) 获取onFulfilled回调函数的返回值即是then方法中第一个函数的返回值 异常处理在then方法中可能会抛出各种异常错误因此需要利用try catch对异常做出处理 没有异常就调用resolve函数将返回值传递给下一个then方法的onFulfilled回调函数 有异常就调用reject函数将error捕获的错误传递给下一个then方法的onRejected回调函数 image-20231010145538010 then方法中抛出错误 p.then(res { console.log(p1:, res) throw xxxx return 1 }).then(res { console.log(p2:, res) }, error { console.log(p2:, error) }) image-20231010145657224 当返回值为MyPromise实例 then (onFulfilled, onRejected) { //... const p2 new MyPromise((resolve, reject) { if (this.state FULFILLED) { setTimeout(() { try { const res onFulfilled(this.result) //1. 处理返回MyPromise实例 if (res instanceof MyPromise) { res.then(res resolve(res), error reject(error)) } else { //将实例返回值传递给下一个then方法的onFulfilled回调函数 resolve(res) } } catch (error) { //处理异常 将错误信息传递给下一个then方法的onRjected回调函数 reject(error) } }, 0); //... } }) return p2 } } const p new MyPromise((resolve, reject) { resolve(success) }) p.then(res { console.log(p1:, res) return new MyPromise((resolve, reject) { resolve(2) // reject(error) }) }).then(res { console.log(p2:, res) //2 }, error { console.log(p2:, error) }) 当第一个then方法返回值如果是MyPromise实例的时候 我们利用 instanceof关键判断res获取的返回值是否是MyPromise实例如果是该实例 通过then方法先获取对应的结果再通过resolve/reject将结果传递给下一个then方法的回调函数 当返回值和接受返回值的实例一致重复引用 const p2 new MyPromise((resolve, reject) { if (this.state FULFILLED) { setTimeout(() { try { const res onFulfilled(this.result) // 处理重复引用 if (res p2) { throw new TypeError(Chaining cycle detected for promise #Promise) } //处理返回MyPromise实例 if (res instanceof MyPromise) { res.then(res resolve(res), error reject(error)) } else { //将实例返回值传递给下一个then方法的onFulfilled回调函数 resolve(res) } } catch (error) { //处理异常 将错误信息传递给下一个then方法的onRjected回调函数 reject(error) } }, 0); } //... }) return p2 const p2 p.then(res { console.log(p1:, res) return p2 }) p2.then(res { console.log(p2:, res) }, error { console.log(p2:, error) }) 当p2 接收then方法的返回值时返回值也是p2在Promise中会直接抛出错误 因此我们也需要判断res 和 p2是否一致如果一致就是重复引用直接抛出错误有catch捕获错误并利用reject传递给下一个then方法中的onRejected回调函数中 image-20231010151110175 抽离函数 我们不仅需要在实例状态为onFulfilled时候对返回值进行处理对于其余两个状态也是需要相同的处理为了实现代码复用将上述处理过程抽离成一个函数 在三种状态中依次调用该方法 //封装函数 处理then方法 function resolvePromise (p2, res, resolve, reject) { //1. 重复引用 直接抛出错误 if (res p2) { throw new TypeError(Chaining cycle detected for promise #Promise) } //2. 返回值是MyPromise实例 利用then获取对应的resolve/reject的值 if (res instanceof MyPromise) { res.then(res resolve(res), error reject(error)) } else { //3.处理普通返回值 resolve(res) } } //then方法 两个参数 onFulfilled, onRejected then (onFulfilled, onRejected) { //... const p2 new MyPromise((resolve, reject) { if (this.state FULFILLED) { setTimeout(() { try { //... resolvePromise(p2, res, resolve, reject) } }, 0); } else if (this.state REJECTED) { setTimeout(() { try { //... resolvePromise(p2, res, resolve, reject) } }, 0); } else if (this.state PENDING) { this.onResolveCallbacks.push(() { setTimeout(() { try { //... resolvePromise(p2, res, resolve, reject) } }, 0); }) this.onRejectCallbacks.push(() { setTimeout(() { try { //... resolvePromise(p2, res, resolve, reject) } }, 0); }) } }) return p2 } 三实现Promise实例方法 核心功能实现之后开始去实现Promise实例上的方法 3.1 catch方法 在之前的示例中有出现过catch方法的示例也大体讲解了下catch方法与then方法之间的联系与关系 引用MDN中对catch方法的论述 Promise 实例的 「catch()」 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象这可以允许你 链式调用其他 promise 的方法 此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式 总结一下 catch方法等同于then(undefined, onRejected) catch() 方法用于捕获并处理 Promise 实例的拒绝状态。当 Promise 实例被拒绝时 catch() 方法会被调用并传递拒绝的原因作为参数。 返回一个 Promise实例 实现 参数onRejected一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值 返回值返回一个新Promise新Promise在返回时总处于待定状态 catch (onRejected) { return this.then(undefined, onRejected) } const p new MyPromise((resolve, reject) { reject(error) }) p.then(res { console.log(res) }).catch(error { console.log(p:, error); //p: error }) 3.2 finally方法 Promise 实例的 「finally()」 方法用于注册一个在 promise 敲定兑现或拒绝时调用的函数。它会立即返回一个等效的 Promise 对象这可以允许你链式调用其他 promise 方法。 如果你想在 promise 敲定时进行一些处理或者清理无论其结果如何那么 finally() 方法会很有用。 总结一下 无论该Promise实例最终是被成功兑现resolve还是被拒绝(reject)finally方法都会被调用 返回一个Promise实例 实现 参数onFinally回调函数 返回值返回一个Promise实例 //finally方法 finally (onFinally) { return this.then(onFinally, onFinally) } const p new MyPromise((resolve, reject) { // reject(error) resolve(success) }) p.then(res { console.log(res) }).catch(error { console.log(p:, error); }).finally(() { console.log(1); // success 1 }) 无论是成功的兑现resolve(success)还是拒绝reject(error)最终都会调用finally函数并执行其中的回调函数 四实现Promise静态方法 Promise还提供了一些静态方法是在构造函数上调用的而不是在实例上调用的 4.1 resolve方法 「Promise.resolve()」 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise那么该 Promise 将被返回如果该值是一个 thenable 对象Promise.resolve() 将调用其 then() 方法及其两个回调函数 Promise中的resolve方法 const p Promise.resolve(1) console.log(p); p1 Promise.resolve(p) console.log(p1); image-20231010203520862 Promise.resolve将给定的1转化为了一个Promise对象 如果再把一个Promise对象传递给Promise.resolve中它不会继续封装该Promise而是将这个Promise对象返回 思路 当接收的值是一个Promise对象时候直接返回该对象 否则返回一个新Promise对象并调用resolve兑现对应的值 实现 参数valueresolve方法接收的值可能为MyPromise 返回值MyPromise static resolve (value) { //是一个MyPromise直接返回 if (value instanceof MyPromise) { return value } //其余转化为MyPromise并返回 return new MyPromise(resolve { resolve(value) }) } 利用instanceof关键字判断value是否为一个MyPromises实例如果是直接返回该MyPromise 返回一个Promise实例并调用resolve兑现该值 即该实例状态直接被转为fulfilled const p MyPromise.resolve(1) console.log(p); const p1 MyPromise.resolve(p) console.log(p1); image-20231010204409551 4.2 reject方法 「Promise.reject()」 静态方法返回一个已拒绝rejected的 Promise 对象拒绝原因为给定的参数。 这个说的就很清楚 返回一个Promise对象 调用reject更改状态为rejected拒绝并把原因传递过去 实现 参数value该 Promise 对象被拒绝的原因。 返回值Promise对象 static reject (value) { //直接返回一个Promise return new MyPromise((undefined, reject) { reject(value) }) } const p MyPromise.reject(error) p.catch(error { console.log(error); }) image-20231010204846632 4.3 race方法 「Promise.race()」 静态方法接受一个 promise 可迭代对象作为输入并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。 总结一下 接收一个promise可迭代对象例如为数组元素都为promise 数组中的所有promise实例进行竞争谁敲定的最快状态改变的最快就返回谁的Promise实例 在promise中 const p1 new Promise((resolve, reject) { setTimeout(() { resolve(p1) }, 1000); }) const p2 p2 const p3 new Promise((resolve, reject) { setTimeout(() { reject(p3) }, 3000); }) const p Promise.race([p1, p2, p3]) p.then(res { console.log(res); }).catch(error { console.log(error); }) image-20231010205639328 设定两个Promise实例和一个基本类型值p1实例设置定时器1秒后兑现结果p2为基本类型值p2p3设置一个定时器3秒后拒绝 调用Promise.race()方法并把p1,p2,p3作为数组传递race方法 race方法内部会先将不是promise对象转化为promise对象然后所有Promise实例进行竞争显然没有设置定时器的p2实例最快返回p2实例 最终通过then方法兑现对应的结果 image-20231010210252921 思路 接收一个数组元素都为Promise实例那么如果接受的不是数组呢抛出错误 返回值为一个Promise实例 遍历数组把不是Promise实例的转化为Promise实例 等待第一个Promise的敲定状态改变 实现 参数iterable可迭代对象例如数组 返回值Promise static race (promises) { //返回一个promsie return new MyPromise((resolve, reject) { //如果参数不是一个数组直接抛出错误 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } //遍历数组等待第一个敲定 promises.forEach(p { //由于p不一定是一个promise 先转化为promise MyPromise.resolve(p).then(res { resolve(res) }, error { reject(error) }) }) }) } 首先返回一个MyPromise实例在其中写对应逻辑 利用Array.isArray方法判断是否为一个数组不是数组抛出错误 遍历数组通过resolve方法将不是Promise实例转化为Promise实例 调用then方法接收Promise实例敲定后传递的结果或拒绝的原因 谁最先敲定改变状态谁直接调用resolve/reject把结果或原因返回 4.4 all方法 「Promise.all()」 静态方法接受一个 Promise 可迭代对象作为输入并返回一个 Promise。当所有输入的 Promise 都被兑现时返回的 Promise 也将被兑现即使传入的是一个空的可迭代对象并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝则返回的 Promise 将被拒绝并带有第一个被拒绝的原因。 总结一下 跟race方法接收参数形式一样都是一个数组元素为Promise实例 返回值为一个Promise实例 等所有的Promise实例全部都被兑现了并将兑现的值按照Promise传入数组的位置依次存放到一个数组中 最后将返回值的Promise实例兑现并把这个结果数组传递 只要其中有Promise拒绝了那么返回的Promise就被拒绝并把原因传递 在Promise中 const p1 new Promise((resolve, reject) { setTimeout(() { resolve(p1) }, 1000); }) const p2 p2 const p3 new Promise((resolve, reject) { setTimeout(() { resolve(p3) }, 3000); }) const p Promise.all([p1, p2, p3]) p.then(res { console.log(res); }).catch(error { console.log(error); }) image-20231010212126512 当数组中的所有Promise实例全部被兑现兑现的值也会按照对应位置存放在一个数组中 等所有Promise实例都被兑现了最终兑现返回的promise实例并把这个结果数组传递 const p1 new Promise((resolve, reject) { setTimeout(() { resolve(p1) }, 1000); }) const p2 p2 const p3 new Promise((resolve, reject) { setTimeout(() { reject(p3) }, 3000); }) const p Promise.all([p1, p2, p3]) p.then(res { console.log(res); }).catch(error { console.log(error); }) 但如果只要有一个promise实例被拒绝了返回的promise直接拒绝 image-20231010213455910 思路 判断参数是否是一个数组不是数组就抛出错误 返回一个Promise实例 如果是空数组直接兑现 遍历数组把数组中不是Promise实例的转化为Promise实例 维护一个数组和一个计数器 遍历数组等待所有Primose兑现 通过索引记录兑现值在数组中的位置保证跟参数中顺序一致 利用计数器计数等待所有promise实例兑现 实现 static all (promises) { //返回一个promise return new MyPromise((resolve, reject) { //不是数组抛出错误 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } //空数组直接兑现 promises.length 0 resolve(promises) const result [] let count 0 //foreach取出全部的promise promises.forEach((p, index) { MyPromise.resolve(p).then(res { //记录结果 result[index] res //判断全部兑现 传递result count count promises.length resolve(result) }, error { //处理拒绝 reject(error) }) }) }) } 还是利用Array.isArray方法判断参数是否为一个数组 判断参数数组是否为空数组空数组直接兑现并把空数组传递 遍历数组中利用resolve方法把不是promise实例的元素转化为priomise实例 通过result[index]索引记录对应的promise实例的兑现值 count计数器等所有的promise实例兑现最后传递result数组 4.5 allSettled方法 「Promise.allSettled()」 静态方法将一个 Promise 可迭代对象作为输入并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时包括传入空的可迭代对象时返回的 Promise 将被兑现并带有描述每个 Promise 结果的对象数组 总结一下 接受参数和返回值与all方法类似 等全部promise实例敲定时all方法是兑现时也就意味着allSettled方法允许出现被拒绝时的状态不会像all方法一样被拒绝时返回值也直接被拒绝 在promise中 const p1 new Promise((resolve, reject) { setTimeout(() { resolve(p1) }, 1000); }) const p2 p2 const p3 new Promise((resolve, reject) { setTimeout(() { reject(p3) }, 3000); }) const p Promise.allSettled([p1, p2, p3]) p.then(res { console.log(res); }).catch(error { console.log(error); }) image-20231010213350301 与all方法不同的是当数组中的promise实例有被拒绝的状态的时候返回的promise也不会直接被拒绝而是会把这个状态记录原因传递其余promise继续兑现 同时与all方法不同的是最终传递的结果数组中是以对象形式 status为fulfilled状态时候另个属性就是value兑现值 statue为rejected状态时候另个属性就是reason拒绝原因 但大体内层逻辑与all方法大体相同 实现 //settled方法 static allSettled (promises) { //返回promise return new MyPromise((resolve, reject) { //判断数组 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } // 为空 promises.length 0 resolve(promises) const result [] let count 0 //遍历数组 promises.forEach((p, index) { MyPromise.resolve(p).then(res { //记录 result[index] { status: FULFILLED, value: res } count count promises.length resolve(result) }, error { result[index] { status: REJECTED, reason: error } count count promises.length resolve(result) }) }) }) } 与all方法不同的是 在兑现或拒绝每个promise实例的时候对于索引记录下是以对象形式存入数组中 无论兑现还是拒绝利用计数器等到全部promise敲定之后再将返回值敲定并把结果数组传递 4.6 any方法 「Promise.any()」 静态方法将一个 Promise 可迭代对象作为输入并返回一个 Promise。当输入的任何一个 Promise 兑现时这个返回的 Promise 将会兑现并返回第一个兑现的值。当所有输入 Promise 都被拒绝包括传递了空的可迭代对象时它会以一个包含拒绝原因数组的 AggregateError 拒绝。 总结一下 接收参数和返回值与all方法类似 但有种像all方法反过来的感觉 只要有一个promise兑现返回值promise立即兑现 all方法是只要有一个promise被拒绝返回值promise直接被拒绝 只有当全部promise实例都被拒绝时候返回值promise才会被拒绝并传递一个拒绝原因的数组 实现 static any (promises) { // 1. 返回Promise,数组判断 return new MyPromise((resolve, reject) { if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } // 2. 空数组直接拒绝 promises.length 0 reject(new AggregateError(promises, All promises were rejected)) // 3. 等待结果 const errors [] let count 0 promises.forEach((p, index) { MyPromise.resolve(p).then(res { // 3.1 第一个兑现 resolve(res) }, err { // 3.2 全部拒绝 errors[index] err count count promises.length reject(new AggregateError(errors, All promises were rejected)) }) }) }) } } 逻辑上是all方法的反过来 五完整代码 function resolvePromise (p2, res, resolve, reject) { //1. 重复引用 直接抛出错误 if (res p2) { throw new TypeError(Chaining cycle detected for promise #Promise) } //2. 返回值是MyPromise实例 利用then获取对应的resolve/reject的值 if (res instanceof MyPromise) { res.then(res resolve(res), error reject(error)) } else { //3.处理普通返回值 resolve(res) } } const PENDING pending const FULFILLED fulfilled const REJECTED rejected class MyPromise { constructor(func) { //初始状态pending this.state PENDING //初始原因undefined this.result undefined //保存成功的回调函数 this.onResolveCallbacks [] //保存失败的回调函数 this.onRejectCallbacks [] //更改状态 const resolve (result) { if (this.state PENDING) { this.state FULFILLED this.result result //遍历执行保存的回调函数 this.onResolveCallbacks.forEach(fn fn()) } }; const reject (result) { if (this.state PENDING) { this.state REJECTED this.result result //遍历执行保存的回调函数 this.onRejectCallbacks.forEach(fn fn()) } }; //捕获错误 try { //执行函数 func(resolve, reject) } catch (error) { reject(error) } } //then方法 两个参数 onFulfilled, onRejected then (onFulfilled, onRejected) { //参数判断 onFulfilled typeof onFulfilled function ? onFulfilled : x x onRejected typeof onRejected function ? onRejected : error { throw error } //链式调用 返回新的promise实例 const p2 new MyPromise((resolve, reject) { //根据状态执行成功失败的回调 if (this.state FULFILLED) { //并把失败的原因传递过去 setTimeout(() { //处理异常 调用reject并把异常传过去 try { //res为p1的返回值 判断是否为promise const res onFulfilled(this.result) resolvePromise(p2, res, resolve, reject) } catch (error) { reject(error) } }, 0); } else if (this.state REJECTED) { setTimeout(() { //使用try catch捕获错误 try { //获取p1返回值 const res onRejected(this.result) resolvePromise(p2, res, resolve, reject) } catch (error) { reject(error) } }, 0); } else if (this.state PENDING) { //保存成功的回调 this.onResolveCallbacks.push(() { setTimeout(() { //处理异常 try { //获取返回值 const res onFulfilled(this.result) resolvePromise(p2, res, resolve, reject) } catch (error) { reject(error) } }, 0); }) //保存失败的回调 this.onRejectCallbacks.push(() { setTimeout(() { //处理异常 try { //获取返回值 const res onRejected(this.result) resolvePromise(p2, res, resolve, reject) } catch (error) { reject(error) } }, 0); }) } }) //返回新的promise实例实现链式调用 return p2 } //catch方法 catch (onRejected) { //调用then中的onRejected回调 return this.then(undefined, onRejected) } //finally方法 finally (onFinally) { return this.then(onFinally, onFinally) } //resolve方法 static resolve (value) { //是一个MyPromise直接返回 if (value instanceof MyPromise) { return value } //其余转化为MyPromise并返回 return new MyPromise(resolve { resolve(value) }) } //reject方法 static reject (value) { //直接返回一个Promise return new MyPromise((undefined, reject) { reject(value) }) } //race方法 static race (promises) { //返回一个promsie return new MyPromise((resolve, reject) { //如果参数不是一个数组直接抛出错误 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } //遍历数组等待第一个敲定 promises.forEach(p { //由于p不一定是一个promise 先转化为promise MyPromise.resolve(p).then(res { resolve(res) }, error { reject(error) }) }) }) } //all方法 static all (promises) { //返回一个promise return new MyPromise((resolve, reject) { //不是数组抛出错误 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } //空数组直接兑现 promises.length 0 resolve(promises) const result [] let count 0 //foreach取出全部的promise promises.forEach((p, index) { MyPromise.resolve(p).then(res { //记录结果 result[index] res //判断全部兑现 传递result count count promises.length resolve(result) }, error { //处理拒绝 reject(error) }) }) }) } //settled方法 static allSettled (promises) { //返回promise return new MyPromise((resolve, reject) { //判断数组 if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } // 为空 promises.length 0 resolve(promises) const result [] let count 0 //遍历数组 promises.forEach((p, index) { MyPromise.resolve(p).then(res { //记录 result[index] { status: FULFILLED, value: res } count count promises.length resolve(result) }, error { result[index] { status: REJECTED, reason: error } count count promises.length resolve(result) }) }) }) } //any方法 static any (promises) { // 1. 返回Promise,数组判断 return new MyPromise((resolve, reject) { if (!Array.isArray(promises)) { return reject(new TypeError(Argument is not iterable)) } // 2. 空数组直接拒绝 promises.length 0 reject(new AggregateError(promises, All promises were rejected)) // 3. 等待结果 const errors [] let count 0 promises.forEach((p, index) { MyPromise.resolve(p).then(res { // 3.1 第一个兑现 resolve(res) }, err { // 3.2 全部拒绝 errors[index] err count count promises.length reject(new AggregateError(errors, All promises were rejected)) }) }) }) } } 六总结 写完身心俱疲但又有种知识充斥在脑海中的感觉以前也只是了解会用promise的几种方法也不了解其中方法的逻辑 只有对其实现一下才会对其更加的掌握现在对promise有了更深的了解了希望在以后使用promise的时候调用其中的方法时候能够想到其中的逻辑是怎么实现的这样能更放心的去使用 参考文章 MDN官方Promise 本文由 mdnice 多平台发布