Ограничение одновременных операций в JavaScript

ogranichenie odnovremennyh operaczij v javascript

Обычно машина, выполняющая наш код, имеет ограниченные ресурсы. Делать все сразу может не только навредить, но и задержать наш процесс и заставить его вообще перестать реагировать.

Когда мы хотим просканировать 100 веб-сайтов, мы должны сканировать, например, 5 сразу, чтобы не скачать всю доступную пропускную способность. Как только один веб-сайт будет просканирован, следующий готов к работе.

Вообще говоря, все «тяжелые» операции следует излагать в срок. Их не следует выполнять сразу для лучшей производительности и экономии ресурсов.

Реализация

Если вы знакомы с моим предыдущим сообщением о реализации обещаний, вы заметите много сходства.

class Concurrently<T = any> {
  private tasksQueue: (() => Promise<T>)[] = [];
  private tasksActiveCount: number = 0;
  private tasksLimit: number;

  public constructor(tasksLimit: number) {
    if (tasksLimit < 0) {
      throw new Error('Limit cant be lower than 0.');
    }

    this.tasksLimit = tasksLimit;
  }

  private registerTask(handler) {
    this.tasksQueue = [...this.tasksQueue, handler];
    this.executeTasks();
  }

  private executeTasks() {
    while (this.tasksQueue.length && this.tasksActiveCount < this.tasksLimit) {
      const task = this.tasksQueue[0];
      this.tasksQueue = this.tasksQueue.slice(1);
      this.tasksActiveCount += 1;

      task()
        .then((result) => {
          this.tasksActiveCount -= 1;
          this.executeTasks();

          return result;
        })
        .catch((err) => {
          this.tasksActiveCount -= 1;
          this.executeTasks();

          throw err;
        });
    }
  }

  public task(handler: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) =>
      this.registerTask(() =>
        handler()
          .then(resolve)
          .catch(reject),
      ),
    );
  }
}

export default Concurrently;

Мы регистрируем заданное задание, добавляя его к нашему очередь задач а затем звоним выполнять задания.

Теперь мы выполняем столько задач, сколько позволяет наш лимит – одна за другой. Каждый раз добавляя 1 к нашему счетчику звоним tasksActiveCount.

Когда выполненное задание закончится, мы удаляем 1 из tasksActiveCount и снова звоните выполнять задания.

Ниже мы можем увидеть пример того, как это работает.

Ограничения установлены на 3. Первые две задачи обрабатываются очень долго. Мы видим, как иногда открывается третий «слот», позволяющий выполнить следующее задание в очереди.

Всегда их три, ни больше, ни меньше.

1*MxACL9-7TXYJTpUTQdJIHQ
Выполнение трудных и легких задач с ограничением 3.

Вы можете увидеть код в репозитории.

Спасибо, что читаете! Можете ли вы придумать другой способ достижения такого же эффекта? Поделитесь ими ниже.

Если у вас есть вопросы или комментарии, не стесняйтесь оставлять их в разделе комментариев ниже или отправлять мне сообщение.

Просмотрите мои социальные сети!

Присоединяйтесь к моей рассылке!

Первоначально опубликовано на www.mcieslar.com 28 августа 2018 года.

Добавить комментарий

Ваш адрес email не будет опубликован.