Использование Promise.all() и Promise.allSettled() для параллельного вызова API в JavaScript
JavaScript

Использование Promise.all() и Promise.allSettled() для параллельного вызова API в JavaScript

Razilator

Promise в JavaScript - это объект, который представляет собой завершение или сбой асинхронной операции. Они часто используются в связке с fetch запросами, чтобы обрабатывать ответы от сервера.

Рассмотрим методы с fetch запросами для паралельного вызова API.

Метод Promise.all()

Promise.all() - это метод, который принимает массив промисов и возвращает новый промис, который разрешается, когда все переданные промисы разрешены. Это позволяет легко выполнять несколько асинхронных операций параллельно.

Пример Promise.all()

index.js
function getTodos() {
  return fetch('https://jsonplaceholder.typicode.com/todos/')
    .then(response => response.json())
}

function getUsers() {
  return fetch('https://jsonplaceholder.typicode.com/users')
    .then(response => response.json())
}

async function get() {
  const [ todos, users ] = await Promise.all([getTodos(), getUsers()])
  console.log(todos);
  console.log(users);
}

Этот код содержит три функции: getTodos, getUsers и get.

Функция getTodos возвращает промис, который выполняет fetch запрос на URL и обрабатывает ответ от сервера, преобразуя его в JSON-формат с помощью метода json.

Функция getUsers аналогична функции getTodos, но выполняет fetch запрос на другой URL.

Функция get является асинхронной и использует ключевое слово await для ожидания выполнения промиса, возвращаемого методом Promise.all().

Этот метод принимает массив из двух промисов, возвращаемых функциями getTodos и getUsers, и возвращает новый промис, который разрешается, когда оба переданных промиса разрешены. Результаты выполнения этих промисов сохраняются в переменных todos и users с помощью деструктуризации массива. Затем эти результаты выводятся в консоль с помощью метода console.log.

В целом, этот код выполняет два параллельных fetch запроса на разные URL-адреса и обрабатывает результаты этих запросов.

Обработка ошибок метода Promise.all()

Если мы захотим обработать ошибку с помощью метода Promise.all(), то мы получим неполную информацию, так как получим ошибку только одного из запросов:

index.js
function getTodos() {
    return fetch('https://jsonplaceholdes.typicode.com/todos/')
        .then(response => response.json())
}

function getUsers() {
    return fetch('https://jsonplaceholdes.typicode.com/users/')
        .then(response => response.json())
}

async function get() {
    try {
        const [todos, users] = await Promise.all([getTodos(), getUsers()])
        console.log(todos);
        console.log(users);
    } catch (e) {
        console.log(e);
    }
}

Ошибка выпадает из первого fetch запроса:

console
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:14294:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 0)
    at async get (C:\Users\Razilator\Desktop\Proghunter\index.js:13:32) {
  cause: Error: getaddrinfo ENOTFOUND jsonplaceholdes.typicode.com
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:107:26) {
    errno: -3008,
    code: 'ENOTFOUND',
    syscall: 'getaddrinfo',
    hostname: 'jsonplaceholdes.typicode.com'
  }
}

Для решения этой проблемы к нам приходит на помощь метод Promise.allSettled().

Метод Promise.allSettled()

Метод Promise.allSettled() принимает на вход итерируемый объект с промисами и возвращает один промис. Этот возвращаемый промис выполняется, когда все промисы из входного итерируемого объекта устанавливаются (включая случай, когда передается пустой итерируемый объект), с массивом объектов, описывающих результат каждого промиса.

Пример Promise.allSettled()

index.js
function getTodos() {
    return fetch('https://jsonplaceholder.typicode.com/todos/')
        .then(response => response.json())
}

function getUsers() {
    return fetch('https://jsonplaceholder.typicode.com/users/')
        .then(response => response.json())
}

async function get() {
    const [todos, users] = await Promise.allSettled([getTodos(), getUsers()])
    console.log(todos);
    console.log(users);
}

Этот код содержит три функции: getTodos, getUsers и get.

Функция getTodos возвращает промис, который выполняет fetch запрос на URL и обрабатывает ответ от сервера, преобразуя его в JSON-формат с помощью метода json.

Функция getUsers аналогична функции getTodos, но выполняет fetch запрос на другой URL.

Функция get является асинхронной и использует ключевое слово await для ожидания выполнения промиса, возвращаемого методом Promise.allSettled(). Этот метод принимает массив из двух промисов, возвращаемых функциями getTodos и getUsers, и возвращает новый промис, который разрешается, когда оба переданных промиса устанавливаются (то есть либо выполняются, либо отклоняются). Результаты выполнения этих промисов сохраняются в переменных todos и users с помощью деструктуризации массива. Затем эти результаты выводятся в консоль с помощью метода console.log.

В целом, этот код выполняет два параллельных fetch запроса на разные URL-адреса и обрабатывает результаты этих запросов. Отличие от предыдущего примера заключается в том, что здесь используется метод Promise.allSettled(), который позволяет обрабатывать как успешно выполненные, так и отклоненные промисы.

Обработка ошибок метода Promise.allSettled()

С помощью метода Promise.allSettled() мы можем обработать ошибку каждого входного fetch запроса, например:

index.js
function getTodos() {
    return fetch('https://jsonplaceholdes.typicode.com/todos/')
        .then(response => response.json())
}

function getUsers() {
    return fetch('https://jsonplaceholdes.typicode.com/users/')
        .then(response => response.json())
}

async function get() {
    const [todosResult, usersResult] = await Promise.allSettled([getTodos(), getUsers()])

    if (todosResult.status === 'rejected') {
        console.error('Error getting todos:', todosResult.reason)
    } else {
        console.log('Todos:', todosResult.value)
    }

    if (usersResult.status === 'rejected') {
        console.error('Error getting users:', usersResult.reason)
    } else {
        console.log('Users:', usersResult.value)
    }
}

Результаты ошибок:

console
Error getting todos: TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:14294:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.allSettled (index 0)
    at async get (C:\Users\Razilator\Desktop\Proghunter\index.js:12:39) {
  cause: Error: getaddrinfo ENOTFOUND jsonplaceholdes.typicode.com
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:107:26) {
    errno: -3008,
    code: 'ENOTFOUND',
    syscall: 'getaddrinfo',
    hostname: 'jsonplaceholdes.typicode.com'
  }
}
Error getting users: TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:14294:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.allSettled (index 1)
    at async get (C:\Users\Razilator\Desktop\Proghunter\index.js:12:39) {
  cause: Error: getaddrinfo ENOTFOUND jsonplaceholdes.typicode.com
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:107:26) {
    errno: -3008,
    code: 'ENOTFOUND',
    syscall: 'getaddrinfo',
    hostname: 'jsonplaceholdes.typicode.com'
  }
}

Метод Promise.allSettled() возвращает массив объектов, каждый из которых описывает результат выполнения соответствующего промиса. Если промис был успешно выполнен, то соответствующий объект имеет свойство status со значением 'fulfilled' и свойство value со значением, которое вернул промис. Если же промис был отклонен (то есть произошла ошибка), то соответствующий объект имеет свойство status со значением 'rejected' и свойство reason с информацией об ошибке.

Таким образом, значение 'rejected' в свойстве status означает, что соответствующий промис был отклонен и произошла ошибка. Информацию об этой ошибке можно получить из свойства reason.

Заключение

Promise - это объект в JavaScript, который представляет собой завершение или сбой асинхронной операции. Он позволяет удобно обрабатывать результаты асинхронных операций и избегать "ада обратных вызовов" (callback hell).

Promise.all() - это метод, который принимает массив промисов и возвращает новый промис, который разрешается, когда все переданные промисы разрешены. Это позволяет легко выполнять несколько асинхронных операций параллельно и обрабатывать их результаты вместе.

Promise.allSettled() - это метод, который также принимает массив промисов, но возвращает новый промис, который разрешается, когда все переданные промисы устанавливаются (то есть либо выполняются, либо отклоняются). Это позволяет обрабатывать как успешно выполненные, так и отклоненные промисы.

В заключение можно сказать, что Promise и его методы all и allSettled являются мощными инструментами для работы с асинхронными операциями в JavaScript. Они позволяют удобно обрабатывать результаты асинхронных операций и избегать сложностей, связанных с управлением асинхронным кодом.

;