我正在try 制作一个由多个队列组成的排队系统,以获取"标题".

import { Subject, timer } from 'rxjs';

enum Title {
  A = 'a',
  B = 'b',
  C = 'c',
}

type Queue = { [key: string]: User[] };
type TitleHolders = { [key: string]: User };
type Timers = { [key: string]: Subject<null> };

const HOLDING_TIME = 10_000;
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
const stamp = () => new Date().toISOString().split('T')[1].split('.')[0];
const log = (data: unknown) => console.log(stamp(), JSON.stringify(data));
const fetchTitle = (title: Title) =>
  sleep(10_000).then(() => ({ success: true }));

class User {
  title: Title | undefined;

  constructor(public name: string) {}

  toString() {
    return `${this.name}: '${this.title}'`;
  }
}

class TitleManager {
  #queue: Queue = {};
  #currentHolders: TitleHolders = {};
  #timers: Timers = {};

  #setTitle(t: Title) {
    if (this.#currentHolders[t]) {
      return;
    }
    const user = this.#queue[t].pop();
    const sub = new Subject<null>();
    sub.subscribe({
      complete: () => {
        const title = user.title;
        delete this.#currentHolders[title];
        delete this.#timers[user.name];
        user.title = undefined;
        log(`>>> '${t}' title REMOVED from ${user.name}`);
        if (this.#queue[title].length) this.#setTitle(title);
      },
    });
    this.#currentHolders[t] ??= user;
    this.#timers[user.name] = sub;
    user.title = t;
    log(`>>> '${t}' title ADDED to ${user.name}`);
    timer(HOLDING_TIME).subscribe(() => sub.complete());
  }

  async giveTitleToUser(t: Title, u: User) {
    this.#queue[t] ??= [];
    this.#queue[t].push(u);
    console.log('starting title request for', u.name);
    const { success } = await fetchTitle(t);
    // Return success status, only set title if if fetching was successful
    if (success) {
      this.#setTitle(t);
    }
  }

  removeUsersTitle(u: User) {
    this.#timers[u.name].complete();
  }
}

const titleManager = new TitleManager();

(async function () {
  const leela = new User('Leela');
  const fry = new User('Fry');

  await titleManager.giveTitleToUser(Title.A, leela);
  await titleManager.giveTitleToUser(Title.A, fry);
})();

(async function () {
  const bender = new User('Bender');

  await sleep(500);
  await titleManager.giveTitleToUser(Title.B, bender);
})();

Link to playground

该队列一次只能处理1,fetchTitle个呼叫.只有当它完成时,它才应该运行下一个.我正在努力想办法实现这一目标.目前,您可以在日志(log)中看到,它启动了fetchTitle个请求中的2个,但没有完成1个请求.如果我可以将成功状态返回给呼叫方,也会很好,但我不知道这是否可能.

推荐答案

以下是我对此的看法:

const userClaimsTitle$$ = new Subject<{ username: string; title: string }>();

userClaimsTitle$$
  .pipe(
    groupBy(({ username }) => username),
    mergeMap((group$) =>
      group$.pipe(
        concatMap(({ title, username }) =>
          concat(
            from(mockFetchTitle(title)).pipe(
              map(() => ({ title, username, type: 'ADDED' } as const))
            ),
            timer(10000).pipe(
              map(() => ({ title, username, type: 'REMOVED' } as const))
            )
          ).pipe(catchError(() => EMPTY))
        )
      )
    ),
    scan((acc, curr) => {
      if (curr.type === 'REMOVED') {
        const copy = { ...acc };
        delete copy[curr.username];
        return copy;
      }

      return { ...acc, [curr.username]: curr.title };
    }, {} as { [username: string]: string })
  )

标题是按人分组的.错误得到了适当的管理.标题在被成功取回之后从它们自己的队列10s中移除.最后,您将获得全局当前状态,以便能够在UI中显示它.

这是一个100,我得到的结果是:

08:19:28 Queueing title a for User-A
08:19:28 Fetching title a for User-A
08:19:28 Queueing title a for User-B
08:19:28 Fetching title a for User-B
08:19:28 Queueing title b for User-A
08:19:33 Title a ADDED for User-A
08:19:33 Global state: {"User-A":"a"}
08:19:33 Title a ADDED for User-B
08:19:33 Global state: {"User-A":"a","User-B":"a"}
08:19:43 Title a REMOVED for User-A
08:19:43 Global state: {"User-B":"a"}
08:19:43 Fetching title b for User-A
08:19:43 Title a REMOVED for User-B
08:19:43 Global state: {}
08:19:48 Title b ADDED for User-A
08:19:48 Global state: {"User-A":"b"}
08:19:58 Title b REMOVED for User-A
08:19:58 Global state: {}

Javascript相关问答推荐

JS、C++和C#给出不同的Base 64 Guid编码结果

为什么从liveWire info js代码传递数组我出现错误?

IMDB使用 puppeteer 加载更多按钮(nodejs)

硬币兑换运行超时

如何解决CORS政策的问题

Angular 17—每当一个布尔变量变为真时触发循环轮询,只要它保持为真

给定一个凸多边形作为一组边,如何根据到最近边的距离填充里面的区域

如何在JavaScript文件中使用Json文件

DOM不自动更新,尽管运行倒计时TS,JS

使用NextJS+MongoDB+Prisma ORM获取无效请求正文,无法发布错误

一个实体一刀VS每个实体多刀S

使用Document.Evaluate() Select 一个包含撇号的HTML元素

在表单集中保存更改时删除';禁用';

Docent.cloneNode(TRUE)不克隆用户输入

不同表的条件API端点Reaction-redux

使用线性插值法旋转直线以查看鼠标会导致 skip

使用可配置项目创建网格

Chrome上的印度时区名S有问题吗?

是否有静态版本的`instanceof`?

由于http.get,*ngIf的延迟很大