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()
- Время, затрачиваемое на выполнение всех промисов, равно самому продолжительному промису.
В приведенных выше задачахtask4
занимает больше всего времени, поэтому общее время, затраченное Promise.all(), равно5000 ms
. - Если какое-либо обещание в переданном списке было отклонено, то непосредственно вызывается блок 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()
- В отличие от Promise.all(), он не замыкается, если какое-либо обещание было отклонено. Он будет продолжать выполнять другие обещания, пока все переданные обещания не будут отклонены или разрешены.
- блок 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()
- Все, что мы передаем в сообщении
reject
, не будет доступно в блоке catch. - Если все обещания были отклонены, будет выдано предопределенное сообщение об ошибке
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.