接着上一篇深入了解Promise机制并使用JS实现一个Promise(一)文章接着使用js来实现一个xpromise
已实现效果
经过上一篇文章我们已近得到下面的代码,实现了promise的状态、值、以及then方法的实现。下面我们接着来实现promise中其他的方法
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};
}export default XPromise;
Promise实例catch方法
定义
Promise 实例的 catch() 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法。此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。
我们看下原生promise.catch的效果
实现
可以看到,一个是返回新的promise
,另一个是可以catch
住之前的onReject
。而.catch
实际上是promise.then(null, onReject)
的一个简写,而我们在之前已经完整实现了promise.then方法,所以只需要直接``return this.then(null, onReject)
即可。完整代码如下:
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}
}export default XPromise;
运行的效果如下所示:
Promise实例finnal方法
定义
finally() 方法返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。这避免了同样的语句需要在 then() 和 catch() 中各写一次的情况。
可以看到finally
有如下几个特征
- 接受一个函数作为参数,但该函数没有参数
- 没有返回
- 下一个
promise.then
对象接受的是finally的上一个then
的返回
实现
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 本质上就是个高阶函数* 是对this.then函数的封装,接受一个fn,* 执行fn之后就走正常的then逻辑即可* 可以理解为对this.then的升阶接受一个函数参数* 高阶函数,类似HOC执行this.then之前执行fn* @param {*} fn * @returns */finally = (fn) => {// finally 函数就是对 this.then 函数包装了一下// 本质还是执行this.then函数,不过在执行原本this.then函数中的onResolved和onReject之前先执行fnreturn this.then(// 这个val就是上一个then的值val => {// 执行传递进来的fnfn && fn();if (val instanceof XPromise) {// 上一个then返回的是promise 通过then获取上一个promise的值,再resolve给下一个then即可return val.then(v => XPromise.resolve(v))} else {return XPromise.resolve(val)}},// 这个error就是上一个then的值error => {fn && fn();if (error instanceof XPromise) {return error.catch(v => XPromise.reject(v))} else {return XPromise.reject(error)}})}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}static race = (promiseList) => {let execute = falsereturn new XPromise((resolve, reject) => {promiseList.forEach(promiseItem => {// 每个promiseItem都是xpromise 那就可以通过.then获取值promiseItem.then(val => {if (execute) return;resolve(val)execute = true}, error => {if (execute) return;reject(error)execute = true})});})}static all = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {}promiseItem.then(val => {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolve// 证明所有promise都是成功的, 整个promise状态也是成功的num ++if (num >= promiseList.length) resolve(result)}, error => {// 在promise数组中有某个promise失败了// 整个promise状态算失败,reject失败最快的那个即可reject(error)})})})}static allSettled = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {};promiseItem.then((val)=> {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)}, error => {// 更新该位置的promise信息result[index]['status'] = "rejected"result[index]['reason'] = error// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)})})})}static any = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的快的promise结果先push入数组const result = []// 用于计数运行了多个个promiselet num = 0// 等每个promise都处理完了,根据每个promise结果决定整个promise的结果const dealResult = () => {// 看能否找到一个成功的promise,先找到的也就是返回最快的promiseconst successPromise = result.find(resultItem => resultItem.status === 'fulfilled')if (successPromise) {resolve(successPromise)} else {throw new Error('All promises were rejected')}}promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象const resultItem = {}promiseItem.then((val)=> {// 更新该位置的promise信息resultItem['status'] = "fulfilled"resultItem['value'] = valresult.push(resultItem)// 如果都运行完了再判断整个Promise的状态num ++if (num >= promiseList.length) dealResult()}, error => {// 更新该位置的promise信息resultItem['status'] = "rejected"resultItem['value'] = errorresult.push(resultItem)// 如果都运行完了再判断整个Promise的状态num ++if (num >= promiseList.length) dealResult()})})})}}export default XPromise;
执行效果如下:
Promise.resolve 静态方法
定义
Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;
实现
我们分析,首先Promise.resolve()
函数接受一个值根据该值的类型做返回即可:
- 非promise:返回一个新的
promise
实例 - promise:直接返回改promise即可
完整代码如下:
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}
}export default XPromise;
代码执行效果如下:
Promise.reject静态方法
定义
Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。
实现
Promise.reject
和Promise.resolve
整体很像这里需要注意的是,根据MDN上的描述,我们知道返回的一定是一个新的promise
对象,所以就不用对入参类型进行判断了
整体代码如下:
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}
}export default XPromise;
代码执行效果如下所示:
Promise.race静态方法
定义
Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。我们看原生的Promise.all
的效果如下:
实现
思路是接受一个promise数组,数组中的每个promise并发执行,谁最先得到结果,将结果返回resolve/reject
掉即可
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}static race = (promiseList) => {let execute = falsereturn new XPromise((resolve, reject) => {promiseList.forEach(promiseItem => {// 每个promiseItem都是xpromise 那就可以通过.then获取值promiseItem.then(val => {if (execute) return;resolve(val)execute = true}, error => {if (execute) return;reject(error)execute = true})});})}
}export default XPromise;
代码执行效果如下:
Promise.all静态方法
定义
Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
实现
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}static race = (promiseList) => {let execute = falsereturn new XPromise((resolve, reject) => {promiseList.forEach(promiseItem => {// 每个promiseItem都是xpromise 那就可以通过.then获取值promiseItem.then(val => {if (execute) return;resolve(val)execute = true}, error => {if (execute) return;reject(error)execute = true})});})}static all = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {}promiseItem.then(val => {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolve// 证明所有promise都是成功的, 整个promise状态也是成功的num ++if (num >= promiseList.length) resolve(result)}, error => {// 在promise数组中有某个promise失败了// 整个promise状态算失败,reject失败最快的那个即可reject(error)})})})}static allSettled = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {};promiseItem.then((val)=> {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)}, error => {// 更新该位置的promise信息result[index]['status'] = "rejected"result[index]['reason'] = error// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)})})})}
}export default XPromise;
代码执行效果如下:
Promise.allSettled静态方法
定义
Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组
实现
代码如下:
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}static race = (promiseList) => {let execute = falsereturn new XPromise((resolve, reject) => {promiseList.forEach(promiseItem => {// 每个promiseItem都是xpromise 那就可以通过.then获取值promiseItem.then(val => {if (execute) return;resolve(val)execute = true}, error => {if (execute) return;reject(error)execute = true})});})}static allSettled = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {};promiseItem.then((val)=> {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)}, error => {// 更新该位置的promise信息result[index]['status'] = "rejected"result[index]['reason'] = error// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)})})})}
}export default XPromise;
代码执行效果如下:
某种意义上Promise.allSettled
方法也是弥补了Promise.all
方法一旦有某一个promise
被拒绝了就拿不到整个结果的缺陷
Promise.any静态方法
定义
Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
实现
class XPromise {constructor(handle) {// 用来记录当前XPromise的状态 pending | fulfilled | rejectedthis["[[PromiseState]]"] = "pending";// 用来记录当前XPromise的值this["[[PromiseResult]]"] = undefined;this.resolveFnList = [];this.rejectFnList = [];// 使用否箭头函数规避this问题, 否则就得这里bind一下// handle(this.#resolve.bind(this), this.#reject.bind(this))handle(this.#resolve, this.#reject);}// 对标promise中的resolve#resolve = (val) => {this["[[PromiseState]]"] = "fulfilled";this["[[PromiseResult]]"] = val;// 将his.resolveFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.resolveFnList, val)};// 对标promise中的reject#reject = (error) => {this["[[PromiseState]]"] = "rejected";this["[[PromiseResult]]"] = error;// 将执行this.rejectFn(val)的时机放入微任务中执行this.#observerAndExecuteFn(this.rejectFnList, error)};// 将.then函数接受的onResolve和onReject函数放在微任务中执行#observerAndExecuteFn = (fnList, promiseResult) => {const executeFnList = () => {let itemFn = null;while (fnList.length) {itemFn = fnList.shift();itemFn(promiseResult);}};const targetNode = document.getElementsByTagName("body")[0];const observe = new MutationObserver(executeFnList);observe.observe(targetNode, {attributes: true,});targetNode.setAttribute("x-promise", "watch");};/*** xpromise实例方法* 1. 在promise resolve/reject之后执行onResolved/onReject* 2. 返回一个新的xpromise实例(新的实例而不是原来的xpromise实例)* @param {*} onResolved * @param {*} onReject * @returns */then = (onResolved, onReject) => {// 返回一个新的xpromise实例return new XPromise((resolve, reject) => {// 在这里需要把当前这个promise的结果拿到// resolveFn是需要push到函数队列中的,接受当前promise实例结果的值const resolveFn = (val) => {const result = onResolved && onResolved(val);if (result instanceof XPromise) {// result 既然是xpromise实例// 那这个xpromise的结果就可以从.then中获取result.then((val) => resolve(val));} else {resolve(result);}};this.resolveFnList.push(resolveFn);const rejectFn = (error) => {onReject && onReject(error);reject(error);};this.rejectFnList.push(rejectFn);});};// promise.then(null, onReject)的简写catch = (onReject) => {return this.then(undefined, onReject)}/*** 根据参数的类别判断* 非promise:返回一个新的`promise`实例* promise:直接返回改promise即可* @param {*} val * @returns */static resolve = (val) => {if (val instanceof XPromise) {return val} else {return new XPromise((resolve) => {resolve(val)})}}static reject = (error) => {return new XPromise((undefined, reject) => {reject(error)})}static race = (promiseList) => {let execute = falsereturn new XPromise((resolve, reject) => {promiseList.forEach(promiseItem => {// 每个promiseItem都是xpromise 那就可以通过.then获取值promiseItem.then(val => {if (execute) return;resolve(val)execute = true}, error => {if (execute) return;reject(error)execute = true})});})}static all = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {}promiseItem.then(val => {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolve// 证明所有promise都是成功的, 整个promise状态也是成功的num ++if (num >= promiseList.length) resolve(result)}, error => {// 在promise数组中有某个promise失败了// 整个promise状态算失败,reject失败最快的那个即可reject(error)})})})}static allSettled = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的promise结果顺序与接入的promise顺序相同故使用new Array(promiseList.length);的方式存结果const result = new Array(promiseList.length);// 用于计数运行了多个个promiselet num = 0promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象result[index] = {};promiseItem.then((val)=> {// 更新该位置的promise信息result[index]['status'] = "fulfilled"result[index]['value'] = val// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)}, error => {// 更新该位置的promise信息result[index]['status'] = "rejected"result[index]['reason'] = error// 如果都运行完了就直接resolvenum ++if (num >= promiseList.length) resolve(result)})})})}static any = (promiseList) => {return new XPromise((resolve, reject) => {// 1. 用于存储每个promise的结果// 2. 返回的快的promise结果先push入数组const result = []// 用于计数运行了多个个promiselet num = 0// 等每个promise都处理完了,根据每个promise结果决定整个promise的结果const dealResult = () => {// 看能否找到一个成功的promise,先找到的也就是返回最快的promiseconst successPromise = result.find(resultItem => resultItem.status === 'fulfilled')if (successPromise) {resolve(successPromise)} else {throw new Error('All promises were rejected')}}promiseList.forEach((promiseItem, index) => {// 每一个结果都是一个对象const resultItem = {}promiseItem.then((val)=> {// 更新该位置的promise信息resultItem['status'] = "fulfilled"resultItem['value'] = valresult.push(resultItem)// 如果都运行完了再判断整个Promise的状态num ++if (num >= promiseList.length) dealResult()}, error => {// 更新该位置的promise信息resultItem['status'] = "rejected"resultItem['value'] = errorresult.push(resultItem)// 如果都运行完了再判断整个Promise的状态num ++if (num >= promiseList.length) dealResult()})})})}}export default XPromise;
代码运行效果如下:
参考文档
promise-catch