Promise 工具箱:手写实现静态方法的完全指南

前言

📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!

🍅 个人主页:************************************************************南木元元****************************************************************


Promise有很多静态方法,本文就来分享下如何实现这些静态方法。

目录

静态方法

实现Promise.resolve和Promise.reject

实现Promise.all

实现Promise.allSettled

实现Promise.race

实现Promise.any

实现finally实例方法

结语


静态方法

静态方法是指直接定义在类上的方法,而不是定义在类实例上的方法。它们可以通过类本身调用,而不需要创建类的实例。静态方法通常用于用于在类级别上操作数据和提供一些实用功能,而不需要实例化对象。比如,可以在 Math 类中定义一些数学计算相关的静态方法。

在上文中,我们已经实现了Promsie中最重要的resolve、reject和then方法,但上文实现的代码是不支持直接使用MyPromise.resolve和MyPromise.reject这种形式的。我们可以在Promise 类上通过static关键字直接定义静态方法,来允许对多个 Promise 对象进行操作或直接创建新的 Promise,而无需实例化一个新的 Promise 对象。

实现Promise.resolve和Promise.reject

MDN上对**Promise.resolve()和Promise.reject()的定义:**

1.Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个thenable对象,Promise.resolve() 将调用其then() 方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。

2.Promise.reject() 静态方法返回一个已拒绝(rejected)的Promise 对象,拒绝原因为给定的参数。

javascript 复制代码
class MyPromise {

    ...

    // resolve 静态方法,返回一个以给定值解析后的Promise对象
    static resolve (param) {
        // 1.传参为Promise,直接返回
        if (param instanceof MyPromise) return param;
        
        // 2.直接返回以该值为成功状态的promise对象
        return new MyPromise(resolve =>  {
            resolve(param);
        });
    }

    // reject 静态方法,返回一个带有拒绝原因(拒绝原因为给定参数)的Promise对象
    static reject (reason) {
        return new MyPromise((resolve, reject) => {
            reject(reason);
        });
    }
}

测试:

javascript 复制代码
MyPromise.resolve().then(() => {
    console.log(0);//0
    return MyPromise.resolve(4);
}).then((res) => {
    console.log(res)//4
})

实现Promise.all

all方法用于将多个Promise实例包装成一个新的Promise实例,只有当所有的Promise实例都成功时,新的Promise实例才会成功。

javascript 复制代码
static all(promises) {
    return new Promise(function(resolve, reject) {
        //传入参数为一个空的可迭代对象,直接resolve
        if (promises.length === 0) {
            resolve([]);
        } else {
            const res = [];
            let count = 0;
            for (let i = 0; i < promises.length; i++) {
                //为什么不直接promise[i].then, 因为promise[i]可能不是一个promise, 也可能是普通值
                Promise.resolve(promises[i]).then((data) => {
                    res[i] = data;
                    count++;
                    if (count === promises.length) {
                        resolve(res);//如果所有Promise都成功,则返回成功结果数组
                    }
                }).catch((err) => {
                    reject(err);//如果有一个Promise失败,则返回这个失败结果
                });
            }
        }
    })
}

测试:

javascript 复制代码
const promise1 = MyPromise.resolve(3);
const promise2 = 42;
const promise3 = new MyPromise((resolve, reject) => {
    setTimeout(resolve, 100, "foo");
});

MyPromise.all([promise1, promise2, promise3]).then((values) => {
    console.log(values); //[3, 42, "foo"]
});

实现Promise.allSettled

Promise.allSettled跟Promise.all类似, 唯一的不同在于, 其不会进行短路, 也就是说当Promise全部处理完成后我们可以拿到每个Promise的状态,而不管其是否处理成功。

当有多个彼此不依赖 的异步任务成功完成时,或者您总是想知道每个Promise的结果时,通常使用它。如果任务相互依赖,或者如果你想立即拒绝其中任何任务Promise.all()方法更合适。

javascript 复制代码
static allSettled(promises) {
    return new Promise(function(resolve, reject) {
        //传入参数为一个空的可迭代对象,直接resolve
        if (promises.length === 0) {
            resolve([]);
        } else {
            const res = [];
            let count = 0;
            for (let i = 0; i < promises.length; i++) {
                //为什么不直接promise[i].then, 因为promise[i]可能不是一个promise, 也可能是普通值
                Promise.resolve(promises[i]).then((data) => {
                    res[i] = {status: 'fulfilled', value: data};
                    count++;
                    if (count === promises.length) {
                        resolve(res);//如果所有Promise都成功,则返回成功结果数组
                    }
                }).catch((err) => {
                    //失败的时候,不直接返回,而是也把当前状态保存到数组中,等执行完毕时一起返回该数组
                    res[i] = {status: 'rejected', value: err};
                    count++;
                    if (count === promises.length) {
                        resolve(res);
                    }
                });
            }
        }
    })
}

测试:

javascript 复制代码
MyPromise.allSettled([
    MyPromise.resolve(33),
    new MyPromise((resolve) => setTimeout(() => resolve(66), 0)),
    99,
    MyPromise.reject(new Error("an error"))
]).then((values) => {
    console.log(values);
});

实现Promise.race

race 的实现:只要有一个 promise 执行完,直接 resolve 并停止执行。

javascript 复制代码
static race(promises) {
    return new Promise(function(resolve, reject) {
        //传入参数为一个空的可迭代对象,直接resolve
        if (promises.length === 0) {
            resolve([]);
        } else {
            for (let i = 0; i < promises.length; i++) {
                //为什么不直接promise[i].then, 因为promise[i]可能不是一个promise, 也可能是普通值
                Promise.resolve(promises[i]).then((data) => {
                    resolve(data); //返回最快的结果
                }).catch((err) => {
                    reject(err); //返回最快的结果
                });
            }
        }
    })
}

测试:

javascript 复制代码
const promise1 = new MyPromise((resolve, reject) => {
    setTimeout(resolve, 500, 'one');
});
const promise2 = new MyPromise((resolve, reject) => {
    setTimeout(resolve, 100, 'two');
});
MyPromise.race([promise1, promise2]).then((value) => {
    console.log(value);	//two
});

实现Promise.any

Promise.any() 静态方法会在任意一个传入的 Promise 成功时,返回该成功的结果。如果所有传入的 Promise 都被拒绝(即失败),它会以AggregateError的形式被拒绝,其中包含所有被拒绝的原因。

javascript 复制代码
static any(promises) {
    return new Promise(function (resolve, reject) {
        //传入参数为一个空的可迭代对象,直接resolve
        if (promises.length === 0) {
            resolve([]);
        } else {
            let count = 0;
            for (let i = 0; i < promises.length; i++) {
                //为什么不直接promise[i].then, 因为promise[i]可能不是一个promise, 也可能是普通值
                Promise.resolve(promises[i])
                .then((data) => {
                    resolve(data); //有一个Promise成功,就返回那个结果
                })
                .catch((err) => {
                    count++;
                    if (count === promises.length) {
                    //当所有输入Promise都被拒绝时,会以一个包含拒绝原因数组的AggregateError拒绝,AggregateError对象代表了包装了多个错误对象的单个错误对象
                    reject(new AggregateError('All promises were rejected')); //所有Promise都失败,就报错
                    }
                });
            }
        }
    });
}

实现finally实例方法

无论Promise是成功还是失败,都会调用finally方法,执行 finally 中传入的函数,并且将值原封不动的往下传,以保证可以继续链式调用。

javascript 复制代码
MyPromise.prototype.finally = function (callback) {
    // 调用then方法,传入两个相同的处理函数,返回一个新的 Promise 对象(保证链式调用)
    return this.then(
        value => {
            // 创建一个新的Promise实例,确保异步执行callback
            return MyPromise.resolve(callback()).then(() => value);
        },
        reason => {
            // 创建一个新的Promise实例,确保异步执行callback
            return MyPromise.resolve(callback()).then(() => { throw reason; });
        }
    );
}

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~

相关推荐
刚刚好ā41 分钟前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
yqcoder2 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
会发光的猪。3 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客3 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
Domain-zhuo4 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
小丁爱养花4 小时前
前端三剑客(三):JavaScript
开发语言·前端·javascript
码农六六4 小时前
vue3封装Element Plus table表格组件
javascript·vue.js·elementui
徐同保4 小时前
el-table 多选改成单选
javascript·vue.js·elementui
快乐小土豆~~4 小时前
el-input绑定点击回车事件意外触发页面刷新
javascript·vue.js·elementui
建群新人小猿5 小时前
会员等级经验问题
android·开发语言·前端·javascript·php