Очереди запросов

В автоматизации браузера с помощью Puppeteer работа с сетевыми запросами играет ключевую роль. Одной из фундаментальных концепций является управление очередями запросов, что позволяет эффективно контролировать нагрузку, ускорять тесты и обеспечивать стабильность взаимодействия с веб-страницей.

Перехват и управление сетевыми запросами

Puppeteer предоставляет механизм interception для контроля запросов. С помощью page.setRequestInterception(true) можно перехватывать каждый сетевой запрос до его отправки на сервер. Это позволяет:

  • Блокировать ненужные ресурсы (картинки, шрифты, сторонние скрипты).
  • Модифицировать заголовки и параметры запросов.
  • Реализовывать подмену ответов для тестирования без реального API.

Пример настройки перехвата запросов:

await page.setRequestInterception(true);

page.on(&
    if (request.resourceType() === 'image') {
        request.abort(); // Блокировка загрузки изображений
    } else {
        request.continue(); // Продолжение обычного запроса
    }
});

Очередь запросов и контроль параллелизма

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

Простейшая реализация очереди:

class RequestQueue {
    constructor(concurrency = 5) {
        this.concurrency = concurrency;
        this.queue = [];
        this.activeCount = 0;
    }

    add(task) {
        this.queue.push(task);
        this.next();
    }

    next() {
        if (this.activeCount >= this.concurrency || this.queue.length === 0) return;
        const task = this.queue.shift();
        this.activeCount++;
        task().finally(() => {
            this.activeCount--;
            this.next();
        });
    }
}

Использование:

const queue = new RequestQueue(3); // максимум 3 параллельных запроса

urls.forEach(url => {
    queue.add(async () => {
        const response = await page.goto(url);
        console.log(`${url} загружен с кодом ${response.status()}`);
    });
});

Такая модель позволяет регулировать нагрузку и избежать конфликтов при тестировании динамических страниц.

Приоритет запросов

В сложных сценариях тестирования может потребоваться управление приоритетом запросов. Например, критические API-запросы нужно обрабатывать первыми, а вспомогательные ресурсы — позже. Для этого очередь можно расширить с поддержкой приоритетов:

class PriorityQueue extends RequestQueue {
    add(task, priority = 0) {
        this.queue.push({ task, priority });
        this.queue.sort((a, b) => b.priority - a.priority);
        this.next();
    }

    next() {
        if (this.activeCount >= this.concurrency || this.queue.length === 0) return;
        const { task } = this.queue.shift();
        this.activeCount++;
        task().finally(() => {
            this.activeCount--;
            this.next();
        });
    }
}

Это позволяет тестировать сложные сценарии с предсказуемой последовательностью загрузки ресурсов.

Обработка ошибок и повторные запросы

Сетевые запросы часто завершаются ошибкой из-за таймаутов, нестабильного интернета или ограничений сервера. В очередях запросов полезно внедрять механизм повторных попыток:

async function fetchWithRetry(url, retries = 3) {
    for (let i = 0; i < retries; i++) {
        try {
            const response = await page.goto(url);
            if (response.ok()) return response;
        } catch (e) {
            if (i === retries - 1) throw e;
        }
    }
}

В комбинации с очередями это позволяет повысить надежность тестов и минимизировать сбои из-за временных проблем с сетью.

Логирование и мониторинг очередей

Для анализа производительности и отладки важно логировать состояние очереди:

queue.add(async () => {
    console.log(`Запуск задачи для ${url}`);
    await page.goto(url);
    console.log(`Завершение задачи для ${url}`);
});

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

Интеграция с тестовыми фреймворками

Очереди запросов идеально интегрируются с фреймворками типа Jest, Mocha или Playwright Test, позволяя контролировать асинхронное поведение в рамках тестов. Через хуки beforeAll и afterAll можно настраивать интерцепторы и инициализировать очередь, а внутри it реализовывать контролируемую загрузку ресурсов.

Итоговые практики

  • Всегда включать перехват запросов для фильтрации и контроля ресурсов.
  • Ограничивать конкурентные запросы с помощью очередей.
  • Использовать приоритеты для критически важных ресурсов.
  • Реализовывать повторные попытки при сетевых сбоях.
  • Вести подробное логирование для отладки и анализа производительности.

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