Пусть у нас есть следующий промис:
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('string');
}, 3000);
});
По завершению промиса выведем его результат в консоль:
promise.then(
function(result) {
console.log(result); // выведет 'string'
}
)
Давайте теперь не будем сразу выводить результат,
а как-то изменим его и вернем через return
:
promise.then(
function(result) {
return result + '!';
}
);
В этом случае мы можем к результату нашего
then применить еще один then, создав тем
самым цепочку методов. При этом в
результат следующего метода будет попадать
то, что вернул через return
предыдущий:
promise.then(
function(result) {
return result + '!';
}
).then(
function(result) {
console.log(result); // выведет 'string!'
}
);
Таким образом можно построить цепочку какой-угодно длины:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).then(
function(result) {
return result + '3';
}
).then(
function(result) {
console.log(result); // выведет 'string123'
}
);
Промисы внутри цепочки
Функции цепочки могут также возвращать промисы.
В этом случае результат этого промиса попадет
в следующий then
:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return new Promise(function(resolve) {
resolve(result + '2'); // этот результат попадет в следующий then
});
}
).then(
function(result) {
return result + '3';
}
).then(
function(result) {
console.log(result); // выведет 'string123'
}
);
Исключительные ситуации
Пусть по каким-то причинам наш промис завершится с ошибкой:
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('error');
}, 3000);
});
В этом случае выполнение кода сразу перейдет
к тому then
, в котором есть функция-обработчик
ошибки, либо в первому catch
, смотря
что встретится раньше.
Вот пример первой ситуации:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
},
function(error) {
// выполнение сразу перейдет сюда
}
).then(
function(result) {
console.log(result);
}
);
Вот пример второй ситуации:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
// выполнение сразу перейдет сюда
}
).then(
function(result) {
console.log(result);
}
);
Функция-обработчик имеет два варианта действий:
если она справилась с исключительной ситуацией,
то может вернуть результат через return
и выполнение продолжится дальше по цепочке.
Если же она не справилась с ошибкой, то может
или ничего не возвращать, или выбросить исключение
через throw
. В этом случае выполнение
перейдет к следующему перехватчику ошибки
(в then
или catch
- что встретится
раньше).
Как правило, все ошибки цепочки перехватываются
в одном месте: в конце цепочки размещается
catch
:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
// попадем сюда в случае ошибки
}
);
При этом исключение может возникнуть в самом
промисе, либо выброшено через throw
в любом звене цепочки:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
if (всеХорошо) {
return result + '2';
} else {
throw new Error('ошибка'); // переходим к ближайшему перехватчику
}
}
)
.then(
function(result) {
return result + '3';
}
).catch(
function(error) {
// ближайший перехватчик
}
);
Учтите, что catch
нужен именно для
диагностики ошибки: она решаема или нет.
Если ошибка решаема, то catch
должен
передать ее решение следующему за собой then
.
А если не решаема (или данный catch
просто не знает как ее решить), то мы должны
или ничего не вернуть или бросить исключение:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
if (ошибкаРешаема) {
return 'данные'; // отправляем на следующий then
} else {
// ничего не возвращаем или бросаем исключение
}
}
).then(
function(result) {
// тут решаем ошибку
}
);