JavaScript
throw
Explica cómo throw interrumpe la ejecución, propaga excepciones entre llamadas y diferencia un fallo del contrato de una salida normal con return.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
- Fundamentos de programación
JavaScript
Explica cómo throw interrumpe la ejecución, propaga excepciones entre llamadas y diferencia un fallo del contrato de una salida normal con return.
throw interrumpe el flujo normal y produce una excepción.
throw new Error("Operation failed");function readUser(user) {
if (user === null) {
throw new Error("User is required");
}
return user.name;
}Cuando se ejecuta throw, el return posterior no se alcanza dentro de esa llamada.
function example() {
console.log("Before");
throw new Error("Failed");
console.log("After");
}"After" no se imprime.
function readConfiguration() {
return parseConfiguration();
}
function parseConfiguration() {
throw new Error("Invalid configuration");
}Si parseConfiguration no captura el error, la excepción sale hacia readConfiguration.
parseConfiguration
↓
readConfiguration
↓
caller
↓
entorno superiorEl proceso continúa hasta encontrar un catch o llegar al host.
throw "failed";
throw 404;
throw null;
throw { code: "FAILED" };Es válido, pero normalmente perjudica el diagnóstico.
try {
throw "failed";
} catch (error) {
error instanceof Error; // false
error.stack;
}Prefiere instancias de Error o subclases.
throw new Error("Failed");Esto proporciona nombre, mensaje, causa opcional y stack trace en runtimes habituales.
Debido a la inserción automática de punto y coma, esto es inválido:
throw
new Error("Failed");JavaScript interpreta una terminación después de throw, pero la sentencia necesita una expresión.
Escribe:
throw new Error(
"Failed",
);function calculateAverage(numbers) {
if (!Array.isArray(numbers)) {
throw new TypeError(
"numbers must be an array",
);
}
if (numbers.length === 0) {
throw new RangeError(
"numbers cannot be empty",
);
}
return numbers.reduce(
(sum, number) => sum + number,
0,
) / numbers.length;
}El contrato necesita una colección no vacía. Lanzar evita producir un resultado engañoso como NaN.
throw puede proteger las precondiciones al inicio.
function transfer({ from, to, amount }) {
if (!from || !to) {
throw new TypeError(
"Both accounts are required",
);
}
if (!Number.isFinite(amount)) {
throw new TypeError(
"amount must be finite",
);
}
if (amount <= 0) {
throw new RangeError(
"amount must be positive",
);
}
// Flujo principal.
}Las condiciones inválidas quedan separadas del camino válido.
return null;Representa una salida normal definida por la función.
throw new Error("Failed");Indica que la función no completó normalmente.
Una búsqueda puede retornar ausencia:
function findProduct(products, id) {
return (
products.find(
(product) => product.id === id,
) ?? null
);
}Una operación que exige el producto puede lanzar:
function requireProduct(products, id) {
const product = findProduct(products, id);
if (!product) {
throw new ProductNotFoundError(id);
}
return product;
}Los nombres find y require ayudan a comunicar contratos distintos.
Dentro de una función async, lanzar produce una promesa rechazada.
async function loadUser() {
throw new Error("Cannot load user");
}Conceptualmente, el consumidor debe manejar el rechazo:
await loadUser();Con await dentro de un try, la excepción vuelve a sentirse como propagación estructurada. El detalle se estudiará en asincronía.
Un catch puede decidir no manejar completamente el error.
try {
performOperation();
} catch (error) {
logError(error);
throw error;
}throw error conserva el mismo objeto.
También puede añadirse contexto con una nueva causa.
try {
parseConfiguration(content);
} catch (cause) {
throw new ConfigurationError(
"Application configuration is invalid",
{ cause },
);
}Esto cambia la abstracción visible, pero mantiene el origen.
function saveOrder(order) {
database.save(order);
notification.send(order);
}Si guardar funciona y la notificación falla, el estado ya cambió. Lanzar comunica un fallo, pero no deshace automáticamente la operación anterior.
Antes de diseñar el error, pregunta:
Las excepciones interrumpen código; no realizan transacciones por sí solas.
const connection = openConnection();
try {
return readData(connection);
} finally {
connection.close();
}El recurso necesita limpieza tanto si la función retorna como si lanza. El detalle de finally aparece en la siguiente nota.
Redundante:
try {
return performOperation();
} catch (error) {
throw error;
}La propagación ya ocurría automáticamente.
Captura solo cuando la capa puede:
function createProduct(data) {
const product = {
name: data.name,
price: Number(data.price),
};
// Mucho código después...
}Si price es inválido, permitir que viaje por varias capas dificulta encontrar el origen.
function createProduct(data) {
const price = Number(data.price);
if (!Number.isFinite(price)) {
throw new TypeError(
"Product price is invalid",
);
}
return {
name: data.name,
price,
};
}Fallar cerca de la frontera inválida reduce estados ambiguos.
throw new Error(
`Database password ${password} failed`,
);Los errores pueden llegar a logs, herramientas externas o respuestas. No incluyas:
Agrega contexto útil mediante identificadores seguros.
throw new Error(
`Cannot load order ${orderId}`,
{ cause },
);function reserveStock(product, quantity) {
if (!Number.isInteger(quantity)) {
throw new TypeError(
"quantity must be an integer",
);
}
if (quantity <= 0) {
throw new RangeError(
"quantity must be positive",
);
}
if (product.stock < quantity) {
throw new InsufficientStockError({
productId: product.id,
requested: quantity,
available: product.stock,
});
}
product.stock -= quantity;
}Los errores técnicos y del dominio expresan motivos diferentes para no continuar.
throw para una bifurcación normal.throw.throw interrumpe la ejecución normal.catch.throw antes de su expresión.return representa una salida normal; throw, un fallo.¿Qué problema tiene este código?
function parseInput(value) {
if (value === "") {
throw
new Error("Input is required");
}
}La sentencia throw no permite una terminación de línea antes de la expresión. Debe escribirse throw new Error(...), aunque el constructor pueda formatearse en varias líneas dentro de sus paréntesis.
try, catch y finally explica cómo una capa puede manejar una excepción, continuar de forma controlada y limpiar recursos.