0.0.4 • Published 4 years ago

@retailwe/common-libs-async-queue v0.0.4

Weekly downloads
-
License
MIT
Repository
-
Last release
4 years ago

异步队列模块

需求背景

  • 多个模块之间,需要调用相同的异步请求,为了减少重复请求,使用队列来缓存相同的请求

设计思路

通过内部维护一个队列 Map,不同的 key 对应的不同的请求,同时对外暴露相关方法来操作这个 Map:

export default class AsyncQueue {
  private asyncSet: Map<string, Array<Promise<any>>>;

  constructor() {
    this.asyncSet = new Map<string, Array<Promise<any>>>();
  }

  /**
   * 缓存指定 key 的异步请求
   */
  public setPromise(key: string, anyPromise: Promise<any>): void {
    const cur = this.asyncSet.get(key) || [];
    if (!cur) {
      // 初始化 key: []
      this.asyncSet.set(key, []);
    }
    cur.push(anyPromise);
    this.asyncSet.set(key, cur);
  }

  /**
   * 获取指定 key 的异步请求
   */
  public getPromise(key: string): Promise<any> | undefined {
    let result;
    const queue = this.asyncSet.get(key);
    if (queue && queue.length) {
      result = queue.pop();
    }
    return result;
  }

  /**
   * cachePromise 缓存请求
   * @param key 唯一索引 Key
   * @param fn  异步请求
   */
  public cachePromise<T>(key: string, fn: () => Promise<T>): () => Promise<T> {
    let cachePromise = this.getPromise<T>(key);
    if (!cachePromise) {
      cachePromise = fn();
      this.setPromise(key, cachePromise);
    }

    // 使用 ! 非空断言
    return () => cachePromise!;
  }

  ....
}

建议项目内部维护唯一单例

使用方式

小程序

建议在 app.ts 中的 globalData 里面,初始化队列:

import AsyncQueue from '@retailwe/common-libs-async-queue';

App({
  globalData: {
    asyncQueue: new AsyncQueue()
  }
});

业务层请求缓存封装

// service 使用
const mockService = async (key: string): Promise<any> => {
  const testPromise = queue.getPromise(key);
  if (testPromise) return testPromise;

  const tempPromise = asyncFn(key);
  queue.setPromise(key, tempPromise);
  const val = await tempPromise;
  return new Promise(resolve => resolve(val));
};

// 单元测试
test('asnycQueue test1', async t => {
  const key1 = 'asyncQueue1';
  const promiseAll = await Promise.all([mockService(key1), mockService(key1)]);
  t.is(queue.getQueue(key1)?.length, 0);
  t.is(JSON.stringify(promiseAll), JSON.stringify([1, 1]));
});

// 通过 cachePromise 直接缓存一个 () => Promise<any> 函数
test.serial('test cachePromise', async t => {
  const key = 'cachePromise';
  const fn1 = queue.cachePromise<number>(key, () => mockPromiseFn(1));
  t.is(queue.getQueue(key)?.length, 1);
  t.is(await fn1(), 1);
  const fn2 = queue.cachePromise<number>(key, () => mockPromiseFn(2));
  // 这里会使用上一次队列的缓存,所以第二次的结果是上一次的结果
  t.is(await fn2(), 1);
  // cache 相同 key, 队列数不变,
  t.is(queue.getQueue(key)?.length, 0);
  // 队列 map.size + 1
  t.is(queue.getQueues().size, 3);
});