Promise.all Promise.any Promise.allУстановлено Promise.race

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

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

p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)

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

Вариант 1: Обещание.все()

Promise.all() принимает массив обещаний, и как только все обещания разрешены, он возвращает an array, содержащий все данные, разрешенные переданными обещаниями, в том порядке, в котором мы передали обещания.

function asyncTask(message, delay) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(message);
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.all([task1, task2, task3, task4]).then(function (results) {
  console.log(results);
});

// results will contain:
Array(4) [ "Task 1 Done", "Task 2 Done", "Task 3 Done", "Task 4 Done" ]

Ключевые выводы о Promise.all()

  1. Время, затрачиваемое на выполнение всех промисов, равно самому продолжительному промису.
    В приведенных выше задачах task4 занимает больше всего времени, поэтому общее время, затраченное Promise.all(), равно 5000 ms .
  2. Если какое-либо обещание в переданном списке было отклонено, то непосредственно вызывается блок catch, независимо от того, были ли разрешены все другие обещания или нет.
function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (message === "Task 3 Done") {
        // Rejecting third task
        reject("Error occured");
      } else {
        resolve(message);
      }
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.all([task1, task2, task3, task4])
  .then(function (results) {
   // this will never be called
    console.log(results);
  })
  .catch(function (error) {
    console.log(error);
  });

// In the console Error occured will be printed.

Вариант 2: Promise.allSettled()

Promise.allSettled() принимает массив обещаний, и как только все обещания либо разрешены, либо отклонены, он возвращает an array, содержащий все данные с разрешенными и отклоненными обещаниями в том порядке, в котором мы передали обещания.

function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (message === "Task 3 Done") {
        reject("Error occured");
      } else {
        resolve(message);
      }
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.allSettled([task1, task2, task3, task4])
  .then(function (results) {
    console.log(results);
  })

// console.log(results) output;
0: Object { status: "fulfilled", value: "Task 1 Done" }
​
1: Object { status: "fulfilled", value: "Task 2 Done" }
​
2: Object { status: "rejected", reason: "Error occured" }
​
3: Object { status: "fulfilled", value: "Task 4 Done" }

Ключевые выводы о Promise.allSettled()

  1. В отличие от Promise.all(), он не замыкается, если какое-либо обещание было отклонено. Он будет продолжать выполнять другие обещания, пока все переданные обещания не будут отклонены или разрешены.
  2. блок catch никогда не вызывается в Promise.allSettled, потому что все данные возвращаются в блоке then с информацией об отклоненных и разрешенных промисах.
function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject("Error occured");
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);

Promise.allSettled([task1])
  .then(function (results) {
    console.log(results);
    // above line will log
    // [{ status: "rejected", reason: "Error occured" }]
  })
  .catch(function (error) {
    console.log(error); // It will never get called.
  });

Вариант 3: Promise.race()

Здесь race буквально означает race среди задач, какая бы promise не была решена или отклонена первой, Promise.race() остановит выполнение и просто вернет данные обещания resolved or rejected.

Подобно Promise.all() и Promise.allSettled(), он также принимает массив или обещания.

function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (message === "Task 3 Done") {
        reject("Error occured");
      } else {
        resolve(message);
      }
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 2000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.race([task1, task2, task3, task4])
  .then(function (result) {
    console.log(result);  // Task 2 Done will be logged in the console
    // Here Task2 has shortest time, so it will win the race.
    // Here result will not be an array.
    // result will be the data returned by resolve method
  })

Что, если отклоненное обещание выиграет гонку?

function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (message === "Task 3 Done") {
        reject("Error occured");
      } else {
        resolve(message);
      }
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200); // Shortest time 200ms
const task4 = asyncTask("Task 4 Done", 5000);

Promise.race([task1, task2, task3, task4])
  .then(function (results) {
    console.log(results);
  })
  .catch(function (error) {
    console.log(error); // Task 3 has shortest time, and it wins the race.
    // Error occured will be logged in the console.
  });

Вариант 4: Promise.any()

Это чем-то похоже на Promise.race . Здесь также происходит гонка.
Но только с хорошими бегунами, если какой-либо бегун упадет во время гонки, гонка не остановится, в отличие от Promise.all . Гонка будет продолжаться до тех пор, пока один из участников не достигнет финиша.

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

Как и все другие вкусы, он также принимает множество обещаний.

function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (message === "Task 3 Done") {
        reject("Error occured");
      } else {
        resolve(message);
      }
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200); // Winner Tasks, but it's being rejected
const task4 = asyncTask("Task 4 Done", 5000);

Promise.any([task1, task2, task3, task4])
  .then(function (results) {
    console.log(results); // Task 2 Done will be logged in the console.
    // Task 2 will win the race, because runner (Task3) 
  })

Что, если каждый бегун (задача) упадет во время гонки, т. е. будет отклонен?

Вызывается блок catch с предопределенным сообщением об ошибке.

function asyncTask(message, delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject("Error occured"); // Passed error message won't be available in catch block.
    }, delay);
  });
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.any([task1, task2, task3, task4])
  .then(function (results) {
    console.log(results);
  })
  .catch(function (error) {
    console.log("error", error);
    // error: AggregateError: All promises were rejected
  });

Ключевые выводы о Promise.any()

  1. Все, что мы передаем в сообщении reject, не будет доступно в блоке catch.
  2. Если все обещания были отклонены, будет выдано предопределенное сообщение об ошибке
    AggregateError: Все обещания были отклонены.

Это все обо всех вариантах промисов. :)

Упражнение: согласно приведенной выше информации, давайте решим простой выходной вопрос.

// Can you Guess what will be printed in the console in case we have empty
// array passed inside all 4 variants of Promises?

Promise.all([])
  .then(function (data) {
    console.log("then block all", data);
  })
  .catch(function () {
    console.log("then block allSettled");
  });

Promise.allSettled([])
  .then(function (data) {
    console.log("then block allSettled", data);
  })
  .catch(function (error) {
    console.log("then block allSettled");
  });

Promise.any([])
  .then(function () {
    console.log("then block any");
  })
  .catch(function (error) {
    console.log("catch block any", error);
  });

Promise.race([])
  .then(function () {
    console.log("then block race");
  })
  .catch(function (error) {
    console.log("catch block race");
  });

.

.

.

.

.

.

Решение:

then block all,  Array [] => In case of Promise.all()

then block allSettled , Array [] => In case of Promise.setteled()

catch block any AggregateError: No Promise in Promise.any was resolved

For Race, nothing will be logged.