背景:
实际工作中,接口写在不同组件中,但是请求却是相同的(有人可能会说为什么接口不提出来,我只能说特殊场景,只能这么做;没必要纠结这个,重点是单例模式使用的这套思想)
下面是单例模式代码:
class Singleton {
static instance;
// 创建实例的时候走这儿,在这儿也要判断是否是否创建了实例,要保证是单例模式
constructor() {
// 承接请求后拿到的结果
this.result;
// 私有属性承接请求
this._request;
// 这是私有属性,不允许外部使用
this._hasFinish = "init"; // 初始值:init,请求进行中:doing,请求已结束:done
// 没实例就创建
if (!Singleton.instance) {
Singleton.instance = this;
}
// 有实例的化,直接返回
return Singleton.instance;
}
// 如果用户使用通过 Singleton.getInstance方式调用,也要保证是单例的
static getInstance() {
// 没实例就创建
if (!this.instance) {
this.instance = new Singleton();
}
// 有实例的化,直接返回
return this.instance;
}
onRequest = async (name, age) => {
// 没请求就赋值
if (!this._request) {
this._request = onHandle(name, age);
}
// 未开始和进行中,都要走进去请求;只有已结束,说明拿到值了,这时候就不用进去发起请求了
if (this._hasFinish !== "done") {
// 不管实例几次,都是同一个请求你
const res = await this._request;
this.result = res;
// 1已结束,就改状态
this._hasFinish = "done";
}
return this.result;
};
// 重置;就会恢复到初始状态,只有在这个状态才能再次发送请求;一旦发送请求后,不重置的话,是没法发请求的;所以必须重置;项目关闭例外;
onReset = () => {
this.result = undefined;
this._request = undefined;
this._hasFinish = "init";
};
}
模拟一个接口请求:
const onHandle = (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name, age });
console.log("测试走了几次");
}, 1000);
});
};
下面是测试用例:
let instance1;
let instance2;
let instance3;
const test = async () => {
// 通过new的方式调用
// instance1 = new Singleton();
// 通过静态方法调用
instance1 = Singleton.getInstance();
const res = await instance1.onRequest("老王", 111);
console.log("1--:", res);
};
const test2 = async () => {
// 通过new的方式调用
// instance2 = new Singleton();
// 通过静态方法调用
instance2 = Singleton.getInstance();
const res = await instance2.onRequest("大刚", 222);
console.log("2--:", res);
};
const test3 = async () => {
// 通过new的方式调用
// instance3 = new Singleton();
// 通过静态方法调用
instance3 = Singleton.getInstance();
const res = await instance3.onRequest("小明", 333);
console.log("3--:", res);
};
// 顺序连着请求,模拟的是页面初始化进来不同页面同时发出的请求
test();
test2();
// 测试否是 是单例
console.log(instance2 === instance1);
// 测试是否 是同一个请求
console.log(instance1.req === instance2.req);
// 延迟了5秒,模拟的是页面初始化完毕,用户点击操作发出的请求
setTimeout(() => {
test3();
}, 5000);
运行结果:
分析:
测试用例中,写了两种方式调用,一种是通过new实例的方式,一种是通过静态方法调用的方式;
模拟了两种场景,起码是满足我工作中的要求;一种场景是不同页面同时调用该接口,另一种是用户操作调用接口;
最后的结果是,不管调用几次,只发送了一次请求;实现了合并请求的目标;
其实,第一种场景是连续请求,其实是只发送了一个公共接口;第二种场景,即用户点击,其实是第一种场景已经拿到结果了,第二种它返回的是上一次的结果。
感悟:研究思想比重复写业务更有乐趣!