• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Stop Hating Try-Catch in JavaScript. Just Use This Pattern.

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
This article is loosely based off my recent video:


Hey everyone, Jason here ?

Let's talk about something that many JavaScript developers love to hate: try-catch.

In this article, I want to explore:

  1. why try-catch can be frustrating
  2. discuss a common solution many have proposed, and
  3. introduce a pattern that I haven't seen enough people talk about
The Problem with try-catch


Consider this function:


function getUserAndPreference() {
try {
const user = getUser();
const preference = getUserPreference(user);
return [user, preference];
} catch (error) {
return null;
}
}

At first glance, this seems fine. But here's the issue: the try block catches all errors within it. That means if getUser or getUserPreference throws an error, or even if there's a typo elsewhere, they all get caught in the same catch block. This makes debugging and maintenance harder as your function grows.

To handle errors more granularly, you might consider wrapping each operation in its own try-catch:


function getUserAndPreference() {
let user: User;
try {
user = getUser();
} catch (error) {
return null;
}

let preference: UserPreference;
try {
preference = getUserPreference(user);
} catch (error) {
return null;
}

return [user, preference];
}

But this pattern has its own issues:

  1. Forced to use let instead of const This pattern requires us to declare the variables and assign them in different scope. This forces us to replace our "supposedly" const to let.
  2. Forced to use explicit typing In the previous example, all variables are typed automatically thanks to TypeScript's type inference. However, this approach forces us to seperate the declaring and assigning of the variables, meaning that TypeScript couldn't determine the variables types at declaration and use implicit any for those variables!

To summarize, the 3 pain-points of try-catch are:

  1. Catch-all behaviour
  2. Forcing let instead of const
  3. Compromising type inference by TypeScript
The "Do Not Throw" Pattern


To address these issues, many developers advocate for a "do not throw" approach. Instead of throwing errors, functions return a tuple containing the error and the result.

Here's a really simple example of such concept:


const tryCatch = async <T>(
promise: Promise<T>,
): Promise<[error: null, result: T] | [error: Error]> => {
try {
return [null, await promise];
} catch (error) {
return [error];
}
};

Usage:


const [error, user] = await tryCatch(getUser());
if (error) {
// handle error
}

This pattern mitigates all 3 issues mentioned in the previous section: allows for more granular error handling, allows for using const, and still keep TypeScript's type inference.

However, I find it not to be the most idiomatic way to JavaScript (handling errors as return values) and requires a utility function that's not standardized which causes never-ending discussions amongst engineers with different background and preferences.

Enter IIFE: Immediately Invoked Function Expression



Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



IIFE, pronounced as Eevee (the Pokémon), is a pattern that's been around since the earliest days of JavaScript.


const user = await (async () => {
try {
return await getUser();
} catch (error) {
return null;
}
})();

By wrapping the operation in an IIFE, we can use try-catch as usual while eliminating all problems with try-catch mentioned previously.

We can apply the same pattern to getUserPreference:


const preference = await (async () => {
try {
return await getUserPreference(user);
} catch (error) {
return null;
}
})();

Now, our function looks like this:


async function getUserAndPreference() {
const user = await (async () => {
try {
return await getUser();
} catch (error) {
return null;
}
})();

if (!user) return null;

const preference = await (async () => {
try {
return await getUserPreference(user);
} catch (error) {
return null;
}
})();

if (!preference) return null;

return [user, preference];
}

This approach allows for granular error handling, maintains code integrity, and leverages type inference—all without any utility functions.

Looking Ahead: Do Expressions


There's a proposal for

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

in JavaScript, currently at stage 1. It aims to bring similar functionality as IIFE but with cleaner syntax:


const getUserAndPreference = async () => {
const user = do {
try {
getUser();
} catch (error) {
// handle errors here
return null; // return from getUserAndPreference
}
};
// ...
};

Once this proposal is accepted as the language standard, try-catch IIFEs can migrate seamlessly to do expressions.

Final Thoughts


try-catch isn't inherently evil. It's how we use it that matters. By leveraging IIFE, we can write cleaner, more maintainable code without relying on external utilities or compromising code integrity.

I hope you found this helpful! If you did, please like, give me a follow, and share with your friends. If you have any questions or ideas, feel free to comment and let me know.

Let me know if you'd like to explore more patterns or have any questions!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу