平时我们常会遇到一些模态框需求,比如加载页面时就可能会弹出一些WebSocket消息模态框、广告模态框、红包模态框等等,如果一次性将模态框全部弹出,就会出现重叠效果,谁先弹出谁后弹出都无法控制,及其不友好。本文致力于解决该问题,利用Promise
的特性对其进行并发控制。
基本思路
无论我们有多少个模态框弹出任务需要执行,但是每次只能执行一个,下一个模态框只能在当前任务执行完后再执行。细节不多说了,直接看代码吧
class Scheduler {
taskList: IPromiseMask[];
_max: number;
cache: IPromiseMask[];
constructor() {
this.taskList = []; // 正在执行任务列表
this._max = 1; // 每次只能执行一个任务
this.cache = []; // 当接收到多余一个任务时,存储其他任务
}
/** */
add(promiseCreator: IPromiseMask) {
return new Promise(() => {
if (this.taskList.length < this._max) {
this.runWork(promiseCreator);
} else {
this.cache.push(promiseCreator);
}
});
}
/** 运行 */
runWork(promiseCreator: IPromiseMask) {
this.taskList.push(promiseCreator);
promiseCreator().then(() => {
// 任务执行完,删除正在执行队列中的当前任务
this.taskList.splice(this.taskList.indexOf(promiseCreator), 1);
if (this.cache.length) {
// 如果缓存队列中还有任务,继续执行
this.runWork(this.cache.shift() as IPromiseMask);
}
});
}
}
// 延迟,模拟模态框消息延迟
const sleep = (wait: number) => {
return new Promise((resolve) => {
setTimeout(resolve, wait);
});
};
// 执行任务
const execute = (task: (resolve: IResolve) => void) => {
return new Promise((resolve: IResolve) => {
task(resolve);
});
};
const scheduler = new Scheduler();
/** 添加任务 */
const addTask = (wait: number, task: (resolve: IResolve) => void) => {
scheduler.add(() => sleep(wait).then(() => execute(task)));
};
// 四个弹窗
addTask(1000, (resolve: IResolve) =>
Confirm.open({
title: '提示',
onClose: () => {
Confirm.close();
resolve();
},
keyboard: () => {
Confirm.close();
resolve();
},
onOk: () => {
Confirm.close();
resolve();
},
maskClosable: false,
children: React.createElement('div', null, '弹窗1'),
}),
);
addTask(1200, (resolve: IResolve) =>
Confirm.open({
title: '提示',
onClose: () => {
Confirm.close();
resolve();
},
keyboard: () => {
Confirm.close();
resolve();
},
onOk: () => {
Confirm.close();
resolve();
},
maskClosable: false,
children: React.createElement('div', null, '弹窗2'),
}),
);
addTask(2000, (resolve: IResolve) =>
Confirm.open({
title: '提示',
onClose: () => {
Confirm.close();
resolve();
},
keyboard: () => {
Confirm.close();
resolve();
},
onOk: () => {
Confirm.close();
resolve();
},
maskClosable: false,
children: React.createElement('div', null, '弹窗3'),
}),
);
addTask(3000, (resolve: IResolve) =>
Confirm.open({
title: '提示',
onClose: () => {
Confirm.close();
resolve();
},
keyboard: () => {
Confirm.close();
resolve();
},
onOk: () => {
Confirm.close();
resolve();
},
maskClosable: false,
children: React.createElement('div', null, '弹窗4'),
}),
);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。