平时我们常会遇到一些模态框需求,比如加载页面时就可能会弹出一些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'),
  }),
);

popup.gif


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。


« 上一篇
前端模块化
下一篇 »
聊聊 webworker