Последовательные и параллельные запросы

Bliss.js предоставляет удобные инструменты для работы с асинхронными операциями в JavaScript, в частности с HTTP-запросами и другими промис-ориентированными действиями. Основная цель библиотеки — упростить управление последовательностью и параллельностью асинхронного кода, сохранив чистоту синтаксиса и улучшив читаемость.


Последовательные запросы

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

Пример последовательного выполнения:

import Bliss from 'bliss.js';

async function fetchSequential() {
    const result1 = await Bliss.request('/api/user/1');
    const userId = result1.id;

    const result2 = await Bliss.request(`/api/posts/${userId}`);
    const posts = result2.posts;

    const result3 = await Bliss.request(`/api/comments/${posts[0].id}`);
    return result3.comments;
}

fetchSequential().then(comments => console.log(comments));

Ключевые моменты:

  • await приостанавливает выполнение функции до завершения промиса.
  • Ошибка в любом запросе блокирует последующие действия, если не применена обработка исключений.
  • Последовательные запросы удобны для цепочек зависимостей, где данные одного запроса необходимы для следующего.

Обработка ошибок:

async function safeSequential() {
    try {
        const result = await Bliss.request('/api/user/1');
        const posts = await Bliss.request(`/api/posts/${result.id}`);
        const comments = await Bliss.request(`/api/comments/${posts[0].id}`);
        return comments;
    } catch (error) {
        console.error('Ошибка при выполнении последовательных запросов:', error);
        return [];
    }
}

Параллельные запросы

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

Пример параллельного выполнения:

import Bliss from 'bliss.js';

async function fetchParallel() {
    const [users, posts, comments] = await Promise.all([
        Bliss.request('/api/users'),
        Bliss.request('/api/posts'),
        Bliss.request('/api/comments')
    ]);

    return { users, posts, comments };
}

fetchParallel().then(data => console.log(data));

Особенности параллельного подхода:

  • Promise.all запускает все промисы одновременно и возвращает массив результатов.
  • Если любой из промисов завершится с ошибкой, вся операция Promise.all будет отклонена.
  • Для частичной обработки успешных результатов можно использовать Promise.allSettled:
async function fetchPartialParallel() {
    const results = await Promise.allSettled([
        Bliss.request('/api/users'),
        Bliss.request('/api/posts'),
        Bliss.request('/api/comments')
    ]);

    return results.map(r => r.status === 'fulfilled' ? r.value : null);
}

Комбинирование последовательности и параллельности

Bliss.js позволяет комбинировать оба подхода для оптимизации производительности. Например, сначала выполняются несколько независимых запросов параллельно, а затем их результаты используются для последовательных запросов:

async function combinedRequests() {
    const [userResult, postResult] = await Promise.all([
        Bliss.request('/api/user/1'),
        Bliss.request('/api/posts/latest')
    ]);

    const comments = await Bliss.request(`/api/comments/${postResult[0].id}`);
    return { user: userResult, post: postResult[0], comments };
}

Преимущества комбинации:

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

Управление большим количеством запросов

Bliss.js интегрирует механизмы ограничения числа одновременно выполняемых промисов, что полезно при работе с API, имеющими ограничения по частоте запросов.

import { Pool } from 'bliss.js';

const pool = new Pool(5); // одновременно максимум 5 запросов

async function fetchWithPool(urls) {
    const promises = urls.map(url => pool.add(() => Bliss.request(url)));
    return Promise.all(promises);
}

Преимущества использования пула:

  • Предотвращает перегрузку сервера или превышение лимита запросов.
  • Позволяет масштабировать обработку больших массивов данных без блокировки основного потока.

Тайм-ауты и отмена запросов

Bliss.js поддерживает тайм-ауты и отмену запросов через встроенный механизм AbortController:

const controller = new AbortController();

const requestPromise = Bliss.request('/api/data', { signal: controller.signal });

// отмена через 2 секунды
setTimeout(() => controller.abort(), 2000);

requestPromise.catch(error => {
    if (error.name === 'AbortError') {
        console.log('Запрос был отменен');
    } else {
        console.error('Ошибка запроса', error);
    }
});

Рекомендации:

  • Использовать тайм-ауты при работе с медленными или ненадежными API.
  • Комбинировать с Promise.race для реализации собственного механизма ограничения времени выполнения запроса.

Резюме ключевых возможностей

  • Последовательные запросы: зависят друг от друга, управляются await, просты для цепочек зависимостей.
  • Параллельные запросы: выполняются одновременно, ускоряют обработку независимых данных, управляются Promise.all и Promise.allSettled.
  • Комбинация подходов: позволяет оптимизировать скорость и порядок выполнения сложных сценариев.
  • Пулы и ограничения: контролируют число одновременных запросов.
  • Тайм-ауты и отмена: обеспечивают стабильность при работе с внешними API.

Bliss.js делает управление асинхронностью в JavaScript наглядным и структурированным, предоставляя гибкие инструменты для создания эффективных сетевых операций.