Методы JavaScript Promises

Как было сказано в статье JavaScript Promises, обещания в JavaScript являются объектом, который представляет собой результат операции, которая не была завершена еще, но будет завершена в какой-то неопределенный момент в будущем.

Сам объект Promise имеет четыре метода:

  • resolve()
  • reject()
  • all()
  • race()

Promise.resolve()

Как правило, когда мы создаем обещания, мы создаем их как функции, которые выполняют некоторые асинхронные операции, которые будут решены (resolve), когда операция завершена (или отклонены (reject), если она завершится ошибкой). Метод Promise.resolve(), однако, возвращает объект Promise, который немедленно решается. Он принимает один аргумент, значение, которое может быть передано функции .then().

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

Пример 1 - Возвращение статических значений как Обещание

Первый вариант использования метода Promise.resolve(), когда нам нужно вернуть статическое значение как обещание. Чтобы сохранить цепочку обещаний, нам нужно возвращать обещания снова и снова. Например, в этой последовательности запросов, мы можем перейти к функции следующего .then(), только когда мы вернем обещание, которое решено.

get(url)  
.then((response) => {
    response = JSON.parse(response);
    const secondURL = response.data.url
    return get( secondURL ); /* Возвращаем другой Promise */
})
.then((response) => {
    response = JSON.parse(response);
    const thirdURL = response.data.url
    return get( thirdURL ); /* Возвращаем другой Promise */
})
.catch((err) => handleError(err) );

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

get(url)  
.then((response) => {
    response = JSON.parse(response);
    const secondURL = response.data.url;
    return Promise.resolve( secondURL ); /* Возвращает вручную созданный Promise */
})
.then((secondURL) => get( secondURL ) )
.catch((err) => handleError(err) );

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

Пример 2 - Запуск цепочки и создание последовательности

Другой пример использования метода Promise.resolve(), когда мы хотим начать цепочку обещаний, но начальное значение, которе нам нужно не обещание. Примером этого может быть то, когда мы хотим динамически создать последовательность обещаний, и нам нужно первоначальное обещание, чтобы начать все это.

Скажем, у нас есть массив JSON файлов, которые мы должны получить. В каждом из этих файлов, есть URL изображения, которое мы должны получить и отобразить на странице. Таким образом, для каждого элемента в массиве JSON файлов, мы хотим сделать следующее (в том порядке, в которой они находятся в массиве):

get(url)  
.then((response) => {
    response = JSON.parse(response);
    displayImage(response.image);
})

Если мы точно знаем количество файлов, которое мы должны обработать, то мы могли бы просто описать каждую из этих задач сами. Но это будет не очень эффективно, и что, если мы не знаем точное количество файлов?

Чтобы решить эту проблему, мы можем перебрать каждый из файлов, а также создать цепочку обещаний. Но, чтобы убедиться, что мы выполняем каждый из файлов в определенной последовательности, мы должны иметь начальное обещание, к которому мы прибавим последующие обещания цепи. Вот как это выглядит:

const dataFiles = ['one.json', 'two.json', 'three.json'];
const sequence = Promise.resolve(); // Начальное Обещание

dataFiles.forEach((dataFile) => {
  // Добавляем в начальное обещание
  sequence = sequence.then(() => {
      return get(url).then((response) => {
        response = JSON.parse(response);
        displayImage(response.image);
    });
  });
});

Так как мы добавляем к уже существующему обещанию, нам нужно чтобы обещание сначало было решено (resolved), чтобы получить начало цепочки.

Promise.reject()

Метод Promise.reject() работает как Promise.resolve(), но с тем отличием, что возвращает объект обещания, который немедленно отвергается (rejected). Он принимает один аргумент, ошибку, которая может быть передана в функцию .catch().

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

get(url)  
.then((response) => {
    if ( response.data.length < 10 /* Может быть любая ручная проверка */ ) {
      return Promise.reject(new Error('Недостаточно данных для продолжения'));
    }
    response = JSON.parse(response);
    const secondURL = response.data.url
    return get( secondURL );
})
.then((response) => {
    response = JSON.parse(response);
    const thirdURL = response.data.url
    return get( thirdURL );
})
.catch((err) => handleError(err) );

Promise.all()

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

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

const promise1 = Promise.resolve('foo');  
const promise2 = new Promise(function(resolve, reject) {  
  setTimeout(resolve, 100, 'bar');
});
const promise3 = 'baz'; // Не обязательно может быть обещание

Promise.all([promise1, promise2, promise3]).then((arrayOfResponses) => {  
  console.log(arrayOfResponses);
  // ['foo', 'bar', 'baz']
});

Однако, если хотя бы одно из обещаний в списке отвергается, все обещания отвергаются (rejected).

const promise1 = Promise.resolve('foo');  
const promise2 = new Promise(function(resolve, reject) {  
  setTimeout(resolve, 100, 'bar');
});
const promise3 = Promise.reject('Error');

Promise.all([promise1, promise2, promise3]).then((arrayOfResponses) => {  
    console.log(arrayOfResponses);
}).catch((err) => {
    console.log(err);
    // 'Ошибка'
});

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

Promise.race()

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

Но в отличии от Promise.all(), этот метод возвращает обещание, как только какое-либо из обещаний в списке будет решено или отклонено, и передает значение или сообщение об ошибке, этого единственного обещания, в .then() или функцию .catch().

const promise1 = new Promise(function(resolve, reject) {  
  setTimeout(resolve, 500, 'foo');
});
const promise2 = new Promise(function(resolve, reject) {  
  setTimeout(resolve, 100, 'bar');
});
const promise3 = new Promise(function(resolve, reject) {  
  setTimeout(resolve, 900, 'baz');
});

Promise.race([promise1, promise2, promise3]).then((response) => {  
  console.log(response);
  // bar
});

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

Перевод статьи с bitsofco.de


Если у Вас возникли вопросы, то для скорейшего получения ответа рекомендуем воспользоваться нашим форумом

Комментарии:

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


Защитный код
Обновить