Finally: примеры (JAVASCRIPT)
finally(onFinally: function): PromiseОсновы функции finally
Конструкция finally не является самостоятельной функцией, а представляет собой блок, который завершает составную инструкцию try...catch...finally. Этот блок кода выполняется всегда, независимо от того, было ли выброшено исключение в блоке try или нет.
Основное назначение finally — разместить код очистки ресурсов, который должен быть выполнен в любом случае. Например, закрытие файловых дескрипторов, очистка таймеров или сброс состояния.
Блок finally не принимает аргументов и не возвращает значений явным образом. Если в блоке finally есть оператор return, throw или break, он переопределит результат выполнения всего блока try...catch.
Простые примеры использования
Базовый пример с успешным выполнением:
try {
console.log('Попытка выполнить код');
// Код без ошибок
} catch (err) {
console.error('Ошибка:', err.message);
} finally {
console.log('Этот блок выполнится всегда');
}
// Вывод:
// Попытка выполнить код
// Этот блок выполнится всегдаПопытка выполнить код Этот блок выполнится всегда
Пример с возникновением ошибки:
try {
console.log('Попытка');
throw new Error('Искусственная ошибка');
} catch (err) {
console.error('Перехвачено:', err.message);
} finally {
console.log('Finally выполнен после ошибки');
}Попытка Перехвачено: Искусственная ошибка Finally выполнен после ошибки
Похожие конструкции в JavaScript
Прямой альтернативы блоку finally не существует, так как его поведение уникально. Однако можно рассмотреть:
- Promise.prototype.finally() — метод промисов, выполняющийся при их разрешении или отклонении. Аналогичен по логике, но работает с асинхронным кодом.
- try...catch без finally — если очистка ресурсов не требуется, можно обойтись только этими блоками.
- Использование деструктуризации и автоматического управления ресурсами через обертки, но это требует дополнительной реализации.
Блок finally предпочтительнее использовать именно для гарантированного кода очистки в синхронных операциях.
Аналоги в других языках
Python использует блок finally в конструкции try...except...finally, который работает аналогично:
try:
print("Попытка")
raise ValueError("Ошибка")
except ValueError as e:
print(f"Перехвачено: {e}")
finally:
print("Выполняется всегда")Попытка Перехвачено: Ошибка Выполняется всегда
PHP также имеет блок finally с похожей семантикой:
try {
echo "Попытка\n";
throw new Exception("Исключение");
} catch (Exception $e) {
echo "Перехвачено: " . $e->getMessage() . "\n";
} finally {
echo "Finally блок\n";
}Попытка Перехвачено: Исключение Finally блок
C++ использует для подобных целей механизм RAII (получение ресурса есть инициализация) и деструкторы, что является идиоматическим подходом для этого языка, а не отдельным блоком кода.
Типичные ошибки
1. Попытка использовать finally без try или catch приводит к синтаксической ошибке:
finally {
console.log('Одинокий finally');
}
// SyntaxError: Illegal finally clauseSyntaxError: Illegal finally clause
2. Непонимание порядка выполнения при наличии return в finally. Значение из finally переопределяет возвращаемое значение:
function test() {
try {
return 'из try';
} catch(err) {
return 'из catch';
} finally {
return 'из finally'; // Это значение будет возвращено
}
}
console.log(test());из finally
3. Игнорирование ошибок, выброшенных в блоке finally, которые могут перекрыть оригинальное исключение.
Изменения в последних версиях
Сам блок finally как часть try...catch существует с первых версий ECMAScript и не претерпел значительных синтаксических изменений. Однако, с появлением ECMAScript 2018 был добавлен метод Promise.prototype.finally() для асинхронных операций, который реализует схожую логику гарантированного выполнения для промисов. Это расширило концепцию finally на асинхронный код.
Расширенные примеры
Использование для гарантированного закрытия ресурса:
let resource = { open: true, data: 'some data' };
try {
console.log('Работа с ресурсом:', resource.data);
// Имитация ошибки в процессе работы
throw new Error('Ошибка при работе');
} catch (err) {
console.error('Произошла ошибка:', err.message);
} finally {
// Гарантированное освобождение ресурса
resource.open = false;
console.log('Ресурс закрыт:', resource.open);
}
console.log('Состояние после:', resource);Работа с ресурсом: some data
Произошла ошибка: Ошибка при работе
Ресурс закрыт: false
Состояние после: { open: false, data: 'some data' }Finally с управлением потоком выполнения:
function complexFlow() {
let counter = 0;
try {
counter++;
if (Math.random() > 0.5) {
throw new Error('Случайная ошибка');
}
return 'Успех';
} catch (e) {
counter++;
throw e; // Пробрасываем ошибку дальше
} finally {
console.log(`Счетчик операций: ${counter}`);
}
}
try {
console.log(complexFlow());
} catch (e) {
console.log('Внешний перехват:', e.message);
}Счетчик операций: 1 Успех // ИЛИ Счетчик операций: 2 Внешний перехват: Случайная ошибка
Вложенные блоки try-catch-finally:
try {
console.log('Внешний try');
try {
console.log('Внутренний try');
throw new Error('Внутренняя ошибка');
} finally {
console.log('Внутренний finally');
}
} catch (err) {
console.log('Внешний catch:', err.message);
} finally {
console.log('Внешний finally');
}Внешний try Внутренний try Внутренний finally Внешний catch: Внутренняя ошибка Внешний finally