Блок finally виконується після try і catch у будь-якому разі. Але якщо він сам завершується через return, throw, break чи continue, це замінює результат усього try...catch.
return у finally ковтає виняток:
function save() {
try {
throw new Error('Диск заповнено');
} finally {
return 'ok';
}
}
save(); // 'ok' - помилка зникла без сліду
І перекриває return з try:
function getStatus() {
try {
return 'from try';
} finally {
return 'from finally';
}
}
getStatus(); // 'from finally'
throw у finally замінює початкову помилку:
try {
throw new Error('справжня причина');
} finally {
cleanup(); // якщо cleanup() кине свою помилку, «справжня причина» загубиться
}
Це особливо підступно: у логах буде помилка прибирання («Cannot read properties of null»), а справжня проблема - прихована.
Що відбувається насправді. Коли try завершується (return, виняток), результат «запам'ятовується», виконується finally, і лише потім запам'ятований результат застосовується. Але якщо finally сам завершився «різко», запам'ятоване відкидається.
Ще одна тонкість - значення return обчислюється до finally:
function f() {
let x = 1;
try {
return x; // повернеться 1
} finally {
x = 2; // змінна змінилася, але значення вже обчислено
}
}
З об'єктом інакше: повертається посилання, і зміна властивостей у finally буде видна.
Правила для finally:
- лише прибирання: закрити, зняти блокування, приховати індикатор;
- ніколи не
return,break,continue- лінтерno-unsafe-finallyловить це автоматично; - прибирання, що саме може впасти, загортати у власний
try...catch, щоб не перекрити основну помилку:
} finally {
try {
await connection.close();
} catch (closeError) {
report(closeError); // повідомити, але не перекрити помилку з try
}
}
Сучасна альтернатива для гарантованого прибирання ресурсів - using з явним керуванням ресурсами (Symbol.dispose): ресурс звільняється автоматично при виході з блоку. Він уже є в TypeScript і поступово з'являється в рушіях JavaScript.
Аналогія з PHP: там return у finally теж перекриває і return, і виняток з try - правило однакове для обох мов.