# @retailwe/common-libs-async-queue

> RetailWe libs

Latest version **0.0.4** (published 2020-09-24) · MIT license · 0 weekly downloads

## Install

```sh
npm install @retailwe/common-libs-async-queue
pnpm add @retailwe/common-libs-async-queue
yarn add @retailwe/common-libs-async-queue
bun add @retailwe/common-libs-async-queue
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.0.4 |
| Published | 2020-09-24 |
| First published | 2020-09-24 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=8.9 |
| Dependencies | 0 |
| Unpacked size | 44 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | gaterking, jeannehuang, jerryc |

## Links

- npm: https://www.npmjs.com/package/@retailwe/common-libs-async-queue
- Repository: git@git.code.tencent.com:tencent-retail-fe/retailwe
- npm.io page: https://npm.io/package/@retailwe/common-libs-async-queue

## Recent versions

- 0.0.4 (latest) — 2020-09-24

## README

# 异步队列模块

## 需求背景

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

## 设计思路

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

```ts
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` 里面，初始化队列：**

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

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

**业务层请求缓存封装**

```ts
// 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);
});
```

---
_Source: https://npm.io/package/@retailwe/common-libs-async-queue · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
