From b44acfa347e40f4fcafd7290c6aa08dfeb9ca4c0 Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 28 Nov 2021 23:03:43 +0200 Subject: [PATCH 01/17] Initial changes --- 1-js/10-error-handling/1-try-catch/article.md | 194 +++++++++--------- images.yml | 12 +- 2 files changed, 107 insertions(+), 99 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index a928da289..ef8bc17dc 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,274 +1,282 @@ -# Error handling, "try...catch" +(!!!) - ПЕРЕВІРИТИ +* приклади коду +* зображення -No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons. +* слово "виключення" не використовував доки воно не згадане вперше в англійській версії -Usually, a script "dies" (immediately stops) in case of an error, printing it to console. +# Робота з помилками, "try...catch" -But there's a syntax construct `try...catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable. +На скільки чудовими програмістами ми б не були, але часом трапляється, що в роботі наших скрипів можуть виникати виключні ситуації. Вони виникають через наші помилки (!!!), непередбачувані вхідні дані від користувачів, помилкові відповіді від сервера або з тисяч інших причин. -## The "try...catch" syntax +Якщо виникають помилки, то скрипти, зазвичай, "помирають" (раптово зупиняються), виводячи інформацію про помилку в консоль. -The `try...catch` construct has two main blocks: `try`, and then `catch`: +Але існує синтаксична конструкція `try...catch`, що дозволяє нам "перехоплювати" помилки, це дає змогу скриптам виконати потрібні дії, а не раптово припинити роботу. + +## "try...catch" синтаксис + +Конструкція `try...catch` містить два головних блоки: `try`, а потім `catch`: ```js try { - // code... + // код... } catch (err) { - // error handling + // код обробки помилки } ``` -It works like this: +Це працює наступним чином: -1. First, the code in `try {...}` is executed. -2. If there were no errors, then `catch (err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`. -3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. +1. В першу чергу виконується код в `try {...}`. +2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця `try` блоку та продовжується поза `catch` блоком. +3. Якщо виникає помилка, тоді виконання в `try` припиняється, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. ![](try-catch-flow.svg) -So, an error inside the `try {...}` block does not kill the script -- we have a chance to handle it in `catch`. +Отже, помилка всередині `try {...}` блоку не призводить до раптового припинення роботи скрипту - ми отримуємо можливість обробити її в `catch`. -Let's look at some examples. +Подивімося на декілька прикладів. -- An errorless example: shows `alert` `(1)` and `(2)`: +- Приклад без виключень: виводить `alert` `(1)` та `(2)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Початок try блоку'); // *!*(1) <--*/!* - // ...no errors here + // ...код без помилок - alert('End of try runs'); // *!*(2) <--*/!* + alert('Кінець try блоку'); // *!*(2) <--*/!* } catch (err) { - alert('Catch is ignored, because there are no errors'); // (3) + alert('Помилок немає, тому catch ігнорується'); // (3) } ``` -- An example with an error: shows `(1)` and `(3)`: +- Приклад з виключенням: виводить `(1)` та `(3)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Початок try блоку'); // *!*(1) <--*/!* *!* - lalala; // error, variable is not defined! + lalala; // помилка, змінна не визначена! */!* - alert('End of try (never reached)'); // (2) + alert('Кінець try блоку (не буде виконано)'); // (2) } catch (err) { - alert(`Error has occurred!`); // *!*(3) <--*/!* + alert(`Виникла помилка!`); // *!*(3) <--*/!* } ``` -````warn header="`try...catch` only works for runtime errors" -For `try...catch` to work, the code must be runnable. In other words, it should be valid JavaScript. +````warn header="`try...catch` працює тільки з виключеннями, що виникають в під час роботи скрипту" +Щоб блок `try...catch` спрацював, код повинен запускатися. Іншими словами, це повинен бути валідний JavaScript. -It won't work if the code is syntactically wrong, for instance it has unmatched curly braces: +Це не спрацює, якщо код містить синтаксичні помилки, наприклад незакриті фігурні дужки: ```js run try { {{{{{{{{{{{{ } catch (err) { - alert("The engine can't understand this code, it's invalid"); + alert("Це не валідний код, рушій його не зрозуміє"); } ``` -The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code. +JavaScript рушій спочатку прочитує код і тільки потім виконує його. Помилки, що виникають протягом фази читання називаються "помилки парсингу", після цих помилок програми не можуть відновити свою роботу. Це виникає через те, що рушій не може зрозуміти код. -So, `try...catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions". +Тому `try...catch` може тільки обробляти помилки, що виникають у правильному коді.Такі помилки називаються "помилки часу виконання" або "виключення". ```` -````warn header="`try...catch` works synchronously" -If an exception happens in "scheduled" code, like in `setTimeout`, then `try...catch` won't catch it: +````warn header="`try...catch` працює синхронно" +Якщо виключення трапляється у коді, що "заплановано до виконання", як `setTimeout`, тоді `try...catch` не зможе перехопити помилку: ```js run try { setTimeout(function() { - noSuchVariable; // script will die here + noSuchVariable; // скрипт припинить свою роботу }, 1000); } catch (err) { - alert( "won't work" ); + alert( "не спрацює" ); } ``` -That's because the function itself is executed later, when the engine has already left the `try...catch` construct. +Це відбувається через те, що функція буде виконана пізніше, коли рушій вже вийде з блоку `try...catch`. -To catch an exception inside a scheduled function, `try...catch` must be inside that function: +Щоб перехопити виключення всередині функції, що заплановано до виконання, `try...catch` повинен бути всередині цієї функції: ```js run setTimeout(function() { - try { - noSuchVariable; // try...catch handles the error! + try { + noSuchVariable; // try...catch опрацює помилку! } catch { - alert( "error is caught here!" ); + alert( "помилку перехоплено тут!" ); } }, 1000); ``` ```` -## Error object +## Об’єкт помилки -When an error occurs, JavaScript generates an object containing the details about it. The object is then passed as an argument to `catch`: +Коли виникає помилка, JavaScript генерує об’єкт, що містить інформацію про неї. Потім цей об'єкт передається як аргумент в `catch`: ```js try { // ... -} catch (err) { // <-- the "error object", could use another word instead of err +} catch (err) { // <-- "об’єкт помилки", можна використати іншу назву замість err // ... } ``` -For all built-in errors, the error object has two main properties: +Для всіх вбудованих помилок об’єкт помилки має дві головні властивості: `name` -: Error name. For instance, for an undefined variable that's `"ReferenceError"`. +: Назва помилки. Наприклад, для невизначеної змінної назва буде `"ReferenceError"`. `message` -: Textual message about error details. +: Текстове повідомлення з додатковою інформацією про помилку. -There are other non-standard properties available in most environments. One of most widely used and supported is: +Існують інші властивості, що доступні в більшості оточень. Одна з найуживаніших та часто підтримується: `stack` : Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes. -For instance: +: Поточний стек викликів: рядок з інформацією про послідовність вкладених викликів, що призвели до помилки. Використовується для налагодження. + +Наприклад: ```js run untrusted try { *!* - lalala; // error, variable is not defined! + lalala; // помилка, змінна не визначена! */!* } catch (err) { alert(err.name); // ReferenceError alert(err.message); // lalala is not defined alert(err.stack); // ReferenceError: lalala is not defined at (...call stack) - // Can also show an error as a whole - // The error is converted to string as "name: message" + // Також можливо вивести всю інформацію про помилку + // Помилку конвертовано в рядок формату "name: message" alert(err); // ReferenceError: lalala is not defined } ``` -## Optional "catch" binding +## Опціональність аргументів "catch" блоку [recent browser=new] -If we don't need error details, `catch` may omit it: +Блок `catch` не обов’язково повинен перехоплювати інформацію про об’єкт помилки: ```js try { // ... -} catch { // <-- without (err) +} catch { // <-- без (err) // ... } ``` -## Using "try...catch" +## Використання "try...catch" -Let's explore a real-life use case of `try...catch`. +Подивімось на реальний приклад використання `try...catch`. -As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values. +Як ми вже знаємо, JavaScript може читати значення у форматі JSON за допомогою методу [JSON.parse(str)](mdn:js/JSON/parse). -Usually it's used to decode data received over the network, from the server or another source. +Зазвичай ми використовуємо його для декодування даних отриманих з сервера чи іншого джерела через мережу. -We receive it and call `JSON.parse` like this: +Ми отримуємо дані та викликаємо `JSON.parse` наступним чином: ```js run -let json = '{"name":"John", "age": 30}'; // data from the server +let json = '{"name":"Іван", "age": 30}'; // дані з серверу *!* -let user = JSON.parse(json); // convert the text representation to JS object +let user = JSON.parse(json); // трансформуємо текстове значення в JS об'єкт */!* -// now user is an object with properties from the string -alert( user.name ); // John +// тепер user це об'єкт, що містить властивості з рядку +alert( user.name ); // Іван alert( user.age ); // 30 ``` -You can find more detailed information about JSON in the chapter. +Ви можете знайти більше інформації про використання JSON в розділі . -**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".** +**Якщо використати `JSON.parse` з неправильно сформованим `json` повідомленням, це призведе до помилки та раптового припинення роботи скрипту.** -Should we be satisfied with that? Of course not! +Така поведінка задовольняє нас? Звичайно ні! -This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message. +Користувач ніколи не дізнається якщо з даними щось трапилося (якщо не відкриє консоль розробника). Люди не очікують, що щось раптово може припинити роботу без будь-якої інформації про помилку. -Let's use `try...catch` to handle the error: +Щоб обробити помилку використаймо `try...catch`: ```js run -let json = "{ bad json }"; +let json = "{ неправильний формат json }"; try { *!* - let user = JSON.parse(json); // <-- when an error occurs... + let user = JSON.parse(json); // <-- тут виникає помилка... */!* - alert( user.name ); // doesn't work + alert( user.name ); // не буде виконано } catch (err) { *!* - // ...the execution jumps here - alert( "Our apologies, the data has errors, we'll try to request it one more time." ); + // ...виконання передається в цей блок + alert( "Перепрошуємо, але дані містять помилки. Ми спробуємо запросити їх ще раз." ); alert( err.name ); alert( err.message ); */!* } ``` -Here we use the `catch` block only to show the message, but we can do much more: send a new network request, suggest an alternative to the visitor, send information about the error to a logging facility, ... . All much better than just dying. +В цьому випадку `catch` блок використано тільки для виведення повідомлення про помилку, але може бути використаним іншим чином: відправити новий запит, запропонувати користувачі інші опції, відправити інформацію про помилку для логування та ін. Будь-який спосіб використання краще, ніж раптове припинення роботи. -## Throwing our own errors +## Створення та викидання власних типів помилок -What if `json` is syntactically correct, but doesn't have a required `name` property? +Уявімо ситуацію, що `json` синтаксично правильний, але не містить необхідного поля `name`. -Like this: +Наприклад: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // неповні дані try { - let user = JSON.parse(json); // <-- no errors + let user = JSON.parse(json); // <-- помилка не виникає *!* - alert( user.name ); // no name! + alert( user.name ); // відсутнє поле name! */!* } catch (err) { - alert( "doesn't execute" ); + alert( "не буде виконано" ); } ``` -Here `JSON.parse` runs normally, but the absence of `name` is actually an error for us. +В такому випадку `JSON.parse` відпрацює без виключень, але відсутність поля `name` є помилкою з нашої точки зору. -To unify error handling, we'll use the `throw` operator. +Ми будемо використовувати оператор `throw` для об’єднання способів обробки помилок. -### "Throw" operator +### Оператор "throw" -The `throw` operator generates an error. +Оператор `throw` використовується для викидання помилки. -The syntax is: +Оператор має синтаксис: ```js -throw +throw <об’єкт помилки> ``` -Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors). +Рушії дозволяє використовувати будь-які значення як об’єкти помилки. Це може бути навіть примітивне значення, як число чи рядок, але краще використовувати об’єкти, що мають властивості `name` та `message` (для сумісності з вбудованим типом помилок). -JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well. +JavaScript має багато вбудованих конструкторів для вбудованих помилок: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` та інші. Також вони можуть бути використаними для створення об’єктів помилок. -Their syntax is: +Синтаксис ініціалізації вбудованих помилок: ```js let error = new Error(message); @@ -278,15 +286,15 @@ let error = new ReferenceError(message); // ... ``` -For built-in errors (not for any objects, just for errors), the `name` property is exactly the name of the constructor. And `message` is taken from the argument. +Для вбудованого типу помилки, властивість `name` має значення імені конструктора, а `message` отримує значення з аргументу. -For instance: +Наприклад: ```js run -let error = new Error("Things happen o_O"); +let error = new Error("Щось трапилось o_O"); alert(error.name); // Error -alert(error.message); // Things happen o_O +alert(error.message); // Щось трапилось o_O ``` Let's see what kind of error `JSON.parse` generates: diff --git a/images.yml b/images.yml index 14fad54ad..6e5168b2a 100644 --- a/images.yml +++ b/images.yml @@ -110,12 +110,12 @@ recursion-pow.svg: recursive call until n==1: '' try-catch-flow.svg: - Begin: '' - No Errors: '' - An error occured in the code: '' - Ignore catch block: '' - Ignore the rest of try: '' - Execute catch block: '' + Begin: "Початок" + No Errors: "Помилка не виникає" + An error occured in the code: "Виникає помилка" + Ignore catch block: "Ігнорування catch блоку" + Ignore the rest of try: "Ігнорування решти try блоку" + Execute catch block: "Виконання catch блоку" 'try {': '' '': '' '}': '' From 85cf52bf6176f99ab6d78269a768b03ea6e4302f Mon Sep 17 00:00:00 2001 From: purusah Date: Tue, 30 Nov 2021 23:59:36 +0200 Subject: [PATCH 02/17] Next step translated --- 1-js/10-error-handling/1-try-catch/article.md | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index ef8bc17dc..902ce3075 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -297,83 +297,83 @@ alert(error.name); // Error alert(error.message); // Щось трапилось o_O ``` -Let's see what kind of error `JSON.parse` generates: +Подивімося на тип помилки, що згенерує `JSON.parse`: ```js run try { - JSON.parse("{ bad json o_O }"); + JSON.parse("{ це не json o_O }"); } catch (err) { *!* alert(err.name); // SyntaxError */!* - alert(err.message); // Unexpected token b in JSON at position 2 + alert(err.message); // expected property name or '}' at line 1 column 3 of the JSON data } ``` -As we can see, that's a `SyntaxError`. +Як бачимо, назва помилки `SyntaxError`. -And in our case, the absence of `name` is an error, as users must have a `name`. +В нашому випадку відсутність властивості `name` є помилкою, оскільки користувачам потрібна інформація з цього поля. -So let's throw it: +Тож давайте викинемо її: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // неповні дані try { - let user = JSON.parse(json); // <-- no errors + let user = JSON.parse(json); // <-- немає помилки if (!user.name) { *!* - throw new SyntaxError("Incomplete data: no name"); // (*) + throw new SyntaxError("Неповні дані: відсутнє поле name"); // (*) */!* } alert( user.name ); } catch (err) { - alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name + alert( "JSON Error: " + err.message ); // JSON Error: Неповні дані: відсутнє поле name } ``` -In the line `(*)`, the `throw` operator generates a `SyntaxError` with the given `message`, the same way as JavaScript would generate it itself. The execution of `try` immediately stops and the control flow jumps into `catch`. +У рядку `(*)` оператор `throw` генерує `SyntaxError` із заданим значення поля `message`, таким же чином це зробив би JavaScript. Виконання коду в блоці `try` одразу припиняється і контроль передається в `catch`. -Now `catch` became a single place for all error handling: both for `JSON.parse` and other cases. +Тепер в блоці `catch` обробляються всі види помилок: від `JSON.parse` та інших випадків. -## Rethrowing +## Повторне викидання помилок -In the example above we use `try...catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing. +В наступному прикладі використаємо `try...catch`, щоб обробити неправильні дані. Але чи може всередині блоку `try {...}` виникнути *інша непередбачувана помилка*? Наприклад, це не просто "неправильні дані", а програміст помилився і забув визначити змінну чи ще щось? -For example: +Наприклад: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // неповні дані try { - user = JSON.parse(json); // <-- forgot to put "let" before user + user = JSON.parse(json); // <-- не поставлено "let" перед user // ... } catch (err) { alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined - // (no JSON Error actually) + // (але перехоплена помилка не пов'язана з JSON Error) } ``` -Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks. +Звичайно таке можливо! Програмісти теж помиляються. Навіть програми з відкритим кодом, що використовуються десятиріччями можуть раптово виявитися вразливими. -In our case, `try...catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug. +В нашому прикладі `try...catch` використовується для перехоплення помилок, що виникають у випадку неповних даних. Але `catch` перехоплює *всі* типи помилок, що виникають в `try`. Тут виникає непередбачувана помилка, але все одно в в повідомленні виводиться `"JSON Error"`. Це неправильна поведінка, що ускладнює налагодження. -To avoid such problems, we can employ the "rethrowing" technique. The rule is simple: +Щоб уникати таких проблем, ми можемо використовувати підхід "повторного викидання помилок". Правило просте: -**Catch should only process errors that it knows and "rethrow" all others.** +**Блок `catch` повинен оброблювати тільки відомі помилки та повторно генерувати всі інші типи помилок.** -The "rethrowing" technique can be explained in more detail as: +Розгляньмо підхід "повторного викидання" покроково: -1. Catch gets all errors. -2. In the `catch (err) {...}` block we analyze the error object `err`. -3. If we don't know how to handle it, we do `throw err`. +1. Конструкція `catch` перехоплює всі помилки. +2. В блоці `catch (err) {...}` ми аналізуємо об'єкт помилки `err`. +3. Якщо ми не знаємо як правильно обробити помилку, ми робимо `throw err`. -Usually, we can check the error type using the `instanceof` operator: +Зазвичай, тип помилки можна перевірити за допомогою оператора `instanceof`: ```js run try { @@ -382,27 +382,27 @@ try { *!* if (err instanceof ReferenceError) { */!* - alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable + alert('ReferenceError'); // "ReferenceError" помилка доступу до невизначеної змінної } } ``` -We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`. +Для визначення класу помилки можливо перевірити властивість `err.name`. Всі вбудовані помилки мають її. Також можна перевірити значення `err.constructor.name`. -In the code below, we use rethrowing so that `catch` only handles `SyntaxError`: +В коді нижче, щоб `catch` опрацьовував тільки `SyntaxError` ми "повторно викидаємо" помилки інших типів. ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // неповні дані try { let user = JSON.parse(json); if (!user.name) { - throw new SyntaxError("Incomplete data: no name"); + throw new SyntaxError("Неповні дані: відсутнє поле name"); } *!* - blabla(); // unexpected error + blabla(); // непередбачувана помилка */!* alert( user.name ); @@ -413,7 +413,7 @@ try { if (err instanceof SyntaxError) { alert( "JSON Error: " + err.message ); } else { - throw err; // rethrow (*) + throw err; // повторне викидання (*) } */!* From 488e6d277e9730758233a36fc06813a7206878d7 Mon Sep 17 00:00:00 2001 From: purusah Date: Wed, 1 Dec 2021 00:20:48 +0200 Subject: [PATCH 03/17] Improvments --- 1-js/10-error-handling/1-try-catch/article.md | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 902ce3075..0dfcf01b4 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -2,17 +2,15 @@ * приклади коду * зображення -* слово "виключення" не використовував доки воно не згадане вперше в англійській версії - # Робота з помилками, "try...catch" -На скільки чудовими програмістами ми б не були, але часом трапляється, що в роботі наших скрипів можуть виникати виключні ситуації. Вони виникають через наші помилки (!!!), непередбачувані вхідні дані від користувачів, помилкові відповіді від сервера або з тисяч інших причин. +На скільки чудовими програмістами ми б не були, але часом трапляється, що в роботі наших скрипів можуть виникати виключні ситуації. Вони виникають через наші помилки, непередбачувані вхідні дані від користувачів, неправильні відповіді від сервера або з тисяч інших причин. -Якщо виникають помилки, то скрипти, зазвичай, "помирають" (раптово зупиняються), виводячи інформацію про помилку в консоль. +Якщо виникають помилки, то скрипти, зазвичай, "помирають" (раптово припиняють роботу) та виводять інформацію про помилку в консоль. -Але існує синтаксична конструкція `try...catch`, що дозволяє нам "перехоплювати" помилки, це дає змогу скриптам виконати потрібні дії, а не раптово припинити роботу. +Але існує синтаксична конструкція `try...catch`, що дозволяє нам "перехоплювати" помилки, що дає змогу скриптам виконати потрібні дії, а не раптово припинити роботу. -## "try...catch" синтаксис +## Синтаксис "try...catch" Конструкція `try...catch` містить два головних блоки: `try`, а потім `catch`: @@ -30,9 +28,9 @@ try { Це працює наступним чином: -1. В першу чергу виконується код в `try {...}`. -2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця `try` блоку та продовжується поза `catch` блоком. -3. Якщо виникає помилка, тоді виконання в `try` припиняється, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. +1. В першу чергу виконується код в блоці `try {...}`. +2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця блоку `try` та продовжується поза `catch` блоком. +3. Якщо виникає помилка, тоді виконання в `try` припиняється і виконання коду продовжується з початку `catch (err)` блоку. Змінна `err` (можна обрати інше ім'я) буде містити об'єкт помилки з додатковою інформацією. ![](try-catch-flow.svg) @@ -81,7 +79,7 @@ try { ````warn header="`try...catch` працює тільки з виключеннями, що виникають в під час роботи скрипту" Щоб блок `try...catch` спрацював, код повинен запускатися. Іншими словами, це повинен бути валідний JavaScript. -Це не спрацює, якщо код містить синтаксичні помилки, наприклад незакриті фігурні дужки: +Це не спрацює, якщо код містить синтаксичні помилки, як-от незакриті фігурні дужки: ```js run try { @@ -91,14 +89,14 @@ try { } ``` -JavaScript рушій спочатку прочитує код і тільки потім виконує його. Помилки, що виникають протягом фази читання називаються "помилки парсингу", після цих помилок програми не можуть відновити свою роботу. Це виникає через те, що рушій не може зрозуміти код. +JavaScript рушій спочатку прочитує код і тільки потім виконує його. Помилки, що виникають у фазі читання називаються "помилки парсингу", вони не можуть бути обробленими і скрипти припиняють свою роботу. Це виникає через те, що рушій не може зрозуміти код. -Тому `try...catch` може тільки обробляти помилки, що виникають у правильному коді.Такі помилки називаються "помилки часу виконання" або "виключення". +Тому `try...catch` може тільки обробляти помилки, що виникають у правильному коді. Такі помилки називаються "помилки часу виконання" або "виключення". ```` ````warn header="`try...catch` працює синхронно" -Якщо виключення трапляється у коді, що "заплановано до виконання", як `setTimeout`, тоді `try...catch` не зможе перехопити помилку: +Якщо виключення трапляється у "запланованому до виконання" коді, як `setTimeout`, тоді `try...catch` не зможе перехопити помилку: ```js run try { @@ -112,7 +110,7 @@ try { Це відбувається через те, що функція буде виконана пізніше, коли рушій вже вийде з блоку `try...catch`. -Щоб перехопити виключення всередині функції, що заплановано до виконання, `try...catch` повинен бути всередині цієї функції: +Щоб перехопити виключення всередині функції запланованої до виконання, `try...catch` повинен бути всередині цієї функції: ```js run setTimeout(function() { try { @@ -197,10 +195,10 @@ try { let json = '{"name":"Іван", "age": 30}'; // дані з серверу *!* -let user = JSON.parse(json); // трансформуємо текстове значення в JS об'єкт +let user = JSON.parse(json); // трансформуємо текстове значення в JS об’єкт */!* -// тепер user це об'єкт, що містить властивості з рядку +// тепер user це об’єкт, що містить властивості з рядку alert( user.name ); // Іван alert( user.age ); // 30 ``` @@ -213,7 +211,7 @@ alert( user.age ); // 30 Користувач ніколи не дізнається якщо з даними щось трапилося (якщо не відкриє консоль розробника). Люди не очікують, що щось раптово може припинити роботу без будь-якої інформації про помилку. -Щоб обробити помилку використаймо `try...catch`: +Для оброблення помилки використаймо `try...catch`: ```js run let json = "{ неправильний формат json }"; @@ -297,7 +295,7 @@ alert(error.name); // Error alert(error.message); // Щось трапилось o_O ``` -Подивімося на тип помилки, що згенерує `JSON.parse`: +Подивімося на тип помилки згенерований функцією `JSON.parse`: ```js run try { @@ -355,7 +353,7 @@ try { // ... } catch (err) { alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined - // (але перехоплена помилка не пов'язана з JSON Error) + // (але перехоплена помилка не пов’язана з JSON Error) } ``` @@ -370,7 +368,7 @@ try { Розгляньмо підхід "повторного викидання" покроково: 1. Конструкція `catch` перехоплює всі помилки. -2. В блоці `catch (err) {...}` ми аналізуємо об'єкт помилки `err`. +2. В блоці `catch (err) {...}` ми аналізуємо об’єкт помилки `err`. 3. Якщо ми не знаємо як правильно обробити помилку, ми робимо `throw err`. Зазвичай, тип помилки можна перевірити за допомогою оператора `instanceof`: From bd91071d6f25bfb6e7b28f3d590509358b52d60e Mon Sep 17 00:00:00 2001 From: purusah Date: Wed, 1 Dec 2021 01:00:08 +0200 Subject: [PATCH 04/17] Images translated --- 1-js/10-error-handling/1-try-catch/article.md | 1 - 1-js/10-error-handling/1-try-catch/try-catch-flow.svg | 2 +- images.yml | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 0dfcf01b4..a7fa5c150 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,6 +1,5 @@ (!!!) - ПЕРЕВІРИТИ * приклади коду -* зображення # Робота з помилками, "try...catch" diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg index ac816e356..a74d0c607 100644 --- a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg +++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg @@ -1 +1 @@ -BeginNo ErrorsAn error occured in the codeIgnore catch blockIgnore the rest of tryExecute catch blocktry { }// code... \ No newline at end of file +ПочатокПомилка не виникаєПомилка виникаєІгнорування catch блокуІгнорування решти try блокуВиконання catch блокуtry { }// code... \ No newline at end of file diff --git a/images.yml b/images.yml index 6e5168b2a..357c267d0 100644 --- a/images.yml +++ b/images.yml @@ -112,7 +112,7 @@ recursion-pow.svg: try-catch-flow.svg: Begin: "Початок" No Errors: "Помилка не виникає" - An error occured in the code: "Виникає помилка" + An error occured in the code: "Помилка виникає" Ignore catch block: "Ігнорування catch блоку" Ignore the rest of try: "Ігнорування решти try блоку" Execute catch block: "Виконання catch блоку" From 992ff4a0cc5166c5b97f1607a2f419f78f502f5c Mon Sep 17 00:00:00 2001 From: purusah Date: Thu, 2 Dec 2021 01:28:01 +0200 Subject: [PATCH 05/17] Almost the end --- 1-js/10-error-handling/1-try-catch/article.md | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index a7fa5c150..002c775e1 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -29,7 +29,7 @@ try { 1. В першу чергу виконується код в блоці `try {...}`. 2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця блоку `try` та продовжується поза `catch` блоком. -3. Якщо виникає помилка, тоді виконання в `try` припиняється і виконання коду продовжується з початку `catch (err)` блоку. Змінна `err` (можна обрати інше ім'я) буде містити об'єкт помилки з додатковою інформацією. +3. Якщо виникає помилка, тоді виконання в `try` припиняється і виконання коду продовжується з початку `catch (err)` блоку. Змінна `err` (можна обрати інше ім’я) буде містити об’єкт помилки з додатковою інформацією. ![](try-catch-flow.svg) @@ -123,7 +123,7 @@ setTimeout(function() { ## Об’єкт помилки -Коли виникає помилка, JavaScript генерує об’єкт, що містить інформацію про неї. Потім цей об'єкт передається як аргумент в `catch`: +Коли виникає помилка, JavaScript генерує об’єкт, що містить інформацію про неї. Потім цей об’єкт передається як аргумент в `catch`: ```js try { @@ -232,7 +232,7 @@ try { } ``` -В цьому випадку `catch` блок використано тільки для виведення повідомлення про помилку, але може бути використаним іншим чином: відправити новий запит, запропонувати користувачі інші опції, відправити інформацію про помилку для логування та ін. Будь-який спосіб використання краще, ніж раптове припинення роботи. +У цьому разі `catch` блок використано тільки для виведення повідомлення про помилку, але може бути використаним іншим чином: відправити новий запит, запропонувати користувачі інші опції, відправити інформацію про помилку для логування та ін. Будь-який спосіб використання краще, ніж раптове припинення роботи. ## Створення та викидання власних типів помилок @@ -255,7 +255,7 @@ try { } ``` -В такому випадку `JSON.parse` відпрацює без виключень, але відсутність поля `name` є помилкою з нашої точки зору. +В такому разі `JSON.parse` відпрацює без виключень, але відсутність поля `name` є помилкою з нашої точки зору. Ми будемо використовувати оператор `throw` для об’єднання способів обробки помилок. @@ -294,7 +294,7 @@ alert(error.name); // Error alert(error.message); // Щось трапилось o_O ``` -Подивімося на тип помилки згенерований функцією `JSON.parse`: +Подивімося на тип помилки, згенерований функцією `JSON.parse`: ```js run try { @@ -309,7 +309,7 @@ try { Як бачимо, назва помилки `SyntaxError`. -В нашому випадку відсутність властивості `name` є помилкою, оскільки користувачам потрібна інформація з цього поля. +У такому разі відсутність властивості `name` є помилкою, оскільки користувачам потрібна інформація з цього поля. Тож давайте викинемо її: @@ -358,7 +358,7 @@ try { Звичайно таке можливо! Програмісти теж помиляються. Навіть програми з відкритим кодом, що використовуються десятиріччями можуть раптово виявитися вразливими. -В нашому прикладі `try...catch` використовується для перехоплення помилок, що виникають у випадку неповних даних. Але `catch` перехоплює *всі* типи помилок, що виникають в `try`. Тут виникає непередбачувана помилка, але все одно в в повідомленні виводиться `"JSON Error"`. Це неправильна поведінка, що ускладнює налагодження. +В нашому прикладі `try...catch` використовується для перехоплення помилок, що виникають у разі неповних даних. Але `catch` перехоплює *всі* типи помилок, що виникають в `try`. Тут виникає непередбачувана помилка, але все одно в в повідомленні виводиться `"JSON Error"`. Це неправильна поведінка, що ускладнює налагодження. Щоб уникати таких проблем, ми можемо використовувати підхід "повторного викидання помилок". Правило просте: @@ -417,11 +417,11 @@ try { } ``` -The error throwing on line `(*)` from inside `catch` block "falls out" of `try...catch` and can be either caught by an outer `try...catch` construct (if it exists), or it kills the script. +Помилка, що виникає в рядку `(*)`, не проходить перевірку в `catch` блоці і повторно викидається. Виключення, після повторної генерації, може знову бути перехопленим конструкцією `try...catch` (якщо вона існує) або призведе до аварійного припинення роботи скрипту. -So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others. +Така поведінка `catch` блоку дає змогу перехоплювати тільки помилки, для яких передбачено правила обробки та "пропускати" решту типів помилок. -The example below demonstrates how such errors can be caught by one more level of `try...catch`: +Приклад нижче демонструє, як реалізувати перехоплення таких помилок ще одним рівнем `try...catch`: ```js run function readData() { @@ -430,13 +430,13 @@ function readData() { try { // ... *!* - blabla(); // error! + blabla(); // помилка! */!* } catch (err) { // ... if (!(err instanceof SyntaxError)) { *!* - throw err; // rethrow (don't know how to deal with it) + throw err; // повторне викидання (обробка іншого типу помилок не передбачена) */!* } } @@ -446,42 +446,42 @@ try { readData(); } catch (err) { *!* - alert( "External catch got: " + err ); // caught it! + alert( "Зовнішнє перехоплення: " + err ); // перехоплено! */!* } ``` -Here `readData` only knows how to handle `SyntaxError`, while the outer `try...catch` knows how to handle everything. +Функція `readData` дозволяє опрацьовувати тільки `SyntaxError` помилки, а зовнішній блок `try...catch` знає як опрацювати будь-який тип. ## try...catch...finally -Wait, that's not all. +Зачекайте, бо це ще не все. -The `try...catch` construct may have one more code clause: `finally`. +Конструкція `try...catch` дозволяє додати ще один блок: `finally`. -If it exists, it runs in all cases: +Якщо він існує, то виконується в будь-якому разі: -- after `try`, if there were no errors, -- after `catch`, if there were errors. +- після `try`, якщо помилка не виникла, +- після `catch`, якщо помилка була перехоплена. -The extended syntax looks like this: +Розширений синтаксис виглядає наступним чином: ```js *!*try*/!* { - ... try to execute the code ... + ... спроба виконати код ... } *!*catch*/!* (err) { - ... handle errors ... + ... обробка помилки ... } *!*finally*/!* { - ... execute always ... + ... завжди буде виконано ... } ``` -Try running this code: +Спробуйте запустити цей код: ```js run try { alert( 'try' ); - if (confirm('Make an error?')) BAD_CODE(); + if (confirm('Помилка потрібна?')) BAD_CODE(); } catch (err) { alert( 'catch' ); } finally { @@ -489,27 +489,27 @@ try { } ``` -The code has two ways of execution: +Код має дві гілки для виконання: -1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`. -2. If you say "No", then `try -> finally`. +1. Якщо відповісти "Гаразд" на "Помилка потрібна?", буде `try -> catch -> finally`. +2. Якщо відповісти "Скасувати", тоді `try -> finally`. -The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome. +Блок `finally` використовується, якщо ми почали виконувати якусь роботу і хочемо завершити її в будь-якому разі. -For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers. +Наприклад, ми хочемо виміряти час роботи функції, що рахує числа Фібоначчі. Для цього ми можемо почати вимірювання на початку виконання і закінчити після. А якщо протягом роботи функції виникне помилка? Зокрема, імплементація `fib(n)` нижче генерує виключення, якщо на вхід подано від’ємне або неціле число. -The `finally` clause is a great place to finish the measurements no matter what. +Конструкція `finally` відмінне місце для завершення вимірювання незалежно від результату. -Here `finally` guarantees that the time will be measured correctly in both situations -- in case of a successful execution of `fib` and in case of an error in it: +Блок `finally` гарантує, що час буде виміряно правильно як в ситуації успішного виконання, так і в разі помилки. ```js run -let num = +prompt("Enter a positive integer number?", 35) +let num = +prompt("Введіть додатне ціле число?", 35) let diff, result; function fib(n) { if (n < 0 || Math.trunc(n) != n) { - throw new Error("Must not be negative, and also an integer."); + throw new Error("Число не повинно бути від’ємним або дробовим."); } return n <= 1 ? n : fib(n - 1) + fib(n - 2); } @@ -526,26 +526,26 @@ try { } */!* -alert(result || "error occurred"); +alert(result || "виникла помилка"); -alert( `execution took ${diff}ms` ); +alert( `виконання тривало ${diff}мс` ); ``` -You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly. +Якщо після запуску коду ввести в число `35` -- скрипт буде виконано без помилок, блок `finally` після блоку `try`. Але якщо ввести `-1` -- одразу буде згенеровано помилку, а виконання код займе `0ms`. Обидва вимірювання будуть проведені правильно. -In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases. +Інакше кажучи, функція може завершуватися через або `return`, або `throw`, але блок `finally` буде завжди виконано. -```smart header="Variables are local inside `try...catch...finally`" -Please note that `result` and `diff` variables in the code above are declared *before* `try...catch`. +```smart header="Змінні визначені всередині `try...catch...finally` є локальними" +Зверніть увагу, змінні `result` та `diff`, в коді вище, оголошено "перед" `try...catch`. -Otherwise, if we declared `let` in `try` block, it would only be visible inside of it. +Якщо ми оголосимо змінну за допомогою `let` в блоці `try` вона залишиться видимою тільки всередині цього блоку. ``` -````smart header="`finally` and `return`" -The `finally` clause works for *any* exit from `try...catch`. That includes an explicit `return`. +````smart header="`finally` та `return`" +Частина `finally` виконається в *будь-якому* разі при виході з `try...catch`. Навіть якщо явно викликати `return`. -In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code. +У прикладі нижче вихід з блоку `try` відбувається за допомогою `return`. Тоді блок `finally` буде виконано одразу перед поверненням виконання до зовнішнього коду. ```js run function func() { @@ -564,7 +564,7 @@ function func() { } } -alert( func() ); // first works alert from finally, and then this one +alert( func() ); // спочатку спрацює alert з finally, а потім в цьому рядку ``` ```` From ef9a3005227e6220fb8d6aff40cde1280e0b5f11 Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 00:24:42 +0200 Subject: [PATCH 06/17] Finalization --- .../1-finally-or-code-after/solution.md | 27 ++++--- .../1-finally-or-code-after/task.md | 22 ++--- 1-js/10-error-handling/1-try-catch/article.md | 81 +++++++++---------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index ec0dabc9a..51272598d 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -1,47 +1,48 @@ -The difference becomes obvious when we look at the code inside a function. +Різниця стає очевидною, якщо ми подивимося на код всередині функції. -The behavior is different if there's a "jump out" of `try...catch`. +Поведінка відрізняється, якщо код може раптово вийти з `try...catch`. -For instance, when there's a `return` inside `try...catch`. The `finally` clause works in case of *any* exit from `try...catch`, even via the `return` statement: right after `try...catch` is done, but before the calling code gets the control. +Наприклад, якщо є `return` всередині `try...catch`. Блок `finally` спрацює для "будь-якого" виходу з `try...catch`, навіть за допомогою `return`. Одразу після виходу `try...catch`, але перед передачею контролю коду, що викликав. ```js run function f() { try { - alert('start'); + alert('початок'); *!* - return "result"; + return "результат"; */!* } catch (err) { /// ... } finally { - alert('cleanup!'); + alert('очищення!'); } } -f(); // cleanup! +f(); // очищення! ``` ...Or when there's a `throw`, like here: +...Або якщо є `throw`: ```js run function f() { try { - alert('start'); - throw new Error("an error"); + alert('початок'); + throw new Error("помилка"); } catch (err) { // ... - if("can't handle the error") { + if("не можу обробити помилку") { *!* throw err; */!* } } finally { - alert('cleanup!') + alert('очищення!') } } -f(); // cleanup! +f(); // очищення! ``` -It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations. +`finally` гарантує очищення. Очищення не спрацює, якщо ми просто додамо код в кінці функції `f`. diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index b6dc81326..1584bd278 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -4,35 +4,35 @@ importance: 5 # Finally or just the code? -Compare the two code fragments. +Порівняй два фрагменти коду. -1. The first one uses `finally` to execute the code after `try...catch`: +1. В першому використовується `finally` для виконання коду `try...catch`: ```js try { - work work + виконання коду } catch (err) { - handle errors + обробка помилок } finally { *!* - cleanup the working space + очищення ресурсів */!* } ``` -2. The second fragment puts the cleaning right after `try...catch`: +2. В другому код очищення відбувається одразу після `try...catch`: ```js try { - work work + виконання коду } catch (err) { - handle errors + обробка помилок } *!* - cleanup the working space + очищення ресурсів */!* ``` -We definitely need the cleanup after the work, doesn't matter if there was an error or not. +Очищення ресурсів потрібно виконати після роботи не залежно від чи буде помилка. -Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters. +Які переваги використання `finally` чи обидва фрагменти коду однакові? Якщо різниця є -- наведіть приклади використання. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 002c775e1..44caf77a7 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -570,34 +570,34 @@ alert( func() ); // спочатку спрацює alert з finally, а пот ````smart header="`try...finally`" -The `try...finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized. +Конструкція `try...finally` може не мати `catch` частини, що також може стати у нагоді. Така конфігурація може бути використана, коли ми хочемо перехоплювати помилку, але потрібно завершити розпочаті задачі. ```js function func() { - // start doing something that needs completion (like measurements) + // розпочато задачу, що потребує завершення (наприклад вимірювання) try { // ... } finally { - // complete that thing even if all dies + // закінчити задачу навіть, якщо все раптово припинило роботу } } ``` -In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function. +В коді вище помилка виникає всередині `try` та завжди передається вище в стеку викликів через відсутність `catch`, але `finally` виконається до того, як потік виконання вийде з функції. ```` -## Global catch +## Глобальний catch ```warn header="Environment-specific" -The information from this section is not a part of the core JavaScript. +Інформація, що наведено в цій секції не є частиною мови JavaScript. ``` -Let's imagine we've got a fatal error outside of `try...catch`, and the script died. Like a programming error or some other terrible thing. +Припустимо, через помилку програміста виключення трапилося поза блоком `try...catch` і призвело до припинення роботи скрипту. -Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc. +Як ми можемо вчинити в такому випадку? Ми можемо логувати помилку, виводити повідомлення користувачу (переважно, користувачі не повинні бачити повідомлення про помилки) тощо. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. +Специфікація не згадує таку можливість, але оточення, зазвичай, надають таку можливість для зручності. Наприклад, Node.js дозволяє викликати [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) для цього. В браузері можна присвоїти функцію спеціальній властивості [window.onerror](mdn:api/GlobalEventHandlers/onerror), що виконається, коли виникне помилка. -The syntax: +Синтаксис: ```js window.onerror = function(message, url, line, col, error) { @@ -606,75 +606,74 @@ window.onerror = function(message, url, line, col, error) { ``` `message` -: Error message. +: Повідомлення помилки. `url` -: URL of the script where error happened. +: URL скрипту, де трапилась помилка. `line`, `col` -: Line and column numbers where error happened. +: Номер рядку та колонки, де трапилась помилка. `error` -: Error object. +: Об’єкт помилки. -For instance: +Приклад: ```html run untrusted refresh height=1 ``` -The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. +Глобальний обробник `window.onerror` не передбачений для відновлювання роботи скрипту, а тільки відправлення повідомлення про помилку розробникам. -There are also web-services that provide error-logging for such cases, like or . +Для логування помилок в таких випадках існують спеціальні веб-сервіси: чи . -They work like this: +Вони працюють наступним чином: -1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages. -2. That JS script sets a custom `window.onerror` function. -3. When an error occurs, it sends a network request about it to the service. -4. We can log in to the service web interface and see errors. +1. Розробник реєструється в сервісі та отримує JS скрипт (чи URL скрипту), який потрібно додати на сторінку. +2. Цей скрипт встановлює власну функцію в `window.onerror`. +3. Коли трапляється помилка скрипт відправляє мережевий запит до цього сервісу. +4. Розробник може зайти в сервіс та переглядати отримані помилки. -## Summary +## Підсумки -The `try...catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it. +Конструкція `try...catch` дозволяє обробляти помилки, що виникають протягом роботи скрипту. Це, в прямому сенсі, дозволяє "спробувати" виконати код та "перехопити" помилки, що можуть виникнути. -The syntax is: +Синтаксис: ```js try { - // run this code + // виконання коду } catch (err) { - // if an error happened, then jump here - // err is the error object + // якщо трапилась помилка, + // передати виконання в цей блок } finally { - // do in any case after try/catch + // завжди виконається після try/catch } ``` -There may be no `catch` section or no `finally`, so shorter constructs `try...catch` and `try...finally` are also valid. +Також ми можемо пропустити секцію `catch` чи `finally`, тому скорочені конструкції `try...catch` та `try...finally` теж валідні. -Error objects have following properties: +Об’єкт помилки має наступні властивості: +- `message` -- розбірливе повідомлення про помилку. +- `name` -- рядок з іменем помилки (назва конструктора помилки). +- `stack` (нестандартна, але широко-підтримувана) -- стек викликів на момент створення помилки. -- `message` -- the human-readable error message. -- `name` -- the string with error name (error constructor name). -- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation. +Ми можемо пропустити отримання об’єкту помилки, якщо використати `catch {` замість `catch (err) {`. -If an error object is not needed, we can omit it by using `catch {` instead of `catch (err) {`. +Також ми можемо генерувати власні помилки за допомогою оператору `throw`. Технічно, будь-що можна передати аргументом в `throw`, але, зазвичай, використовується об'єкт успадкований від вбудованого класу `Error`. Більше про розширення помилок в наступному розділі. -We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter. +*Повторне викидання* -- важливий шаблон в роботі з помилками: переважно блок `catch` знає як обробляти помилки певного типу, тому він повинен знову викидати невідомі типи помилок. -*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know. - -Even if we don't have `try...catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`. +Навіть, якщо ми не використовуємо `try...catch`, більшість оточень дозволяють встановити "глобальний" обробник помилок. В браузерах це `window.onerror`. From 75f544798127a2a9707f4d79509a9d7e4cad68ab Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 00:27:02 +0200 Subject: [PATCH 07/17] Clean up --- 1-js/10-error-handling/1-try-catch/article.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 44caf77a7..5fb310c8a 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,6 +1,3 @@ -(!!!) - ПЕРЕВІРИТИ -* приклади коду - # Робота з помилками, "try...catch" На скільки чудовими програмістами ми б не були, але часом трапляється, що в роботі наших скрипів можуть виникати виключні ситуації. Вони виникають через наші помилки, непередбачувані вхідні дані від користувачів, неправильні відповіді від сервера або з тисяч інших причин. From e494e218cc213a6280324ef4a582f852b45d92a5 Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 00:48:20 +0200 Subject: [PATCH 08/17] Fix image translation --- 1-js/10-error-handling/1-try-catch/try-catch-flow.svg | 2 +- images.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg index a74d0c607..a7db4243d 100644 --- a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg +++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg @@ -1 +1 @@ -ПочатокПомилка не виникаєПомилка виникаєІгнорування catch блокуІгнорування решти try блокуВиконання catch блокуtry { }// code... \ No newline at end of file +ПочатокПомилка не виникаєПомилка виникаєІгнорування catch блокуІгнорування решти try блокуВиконання catch блокуtry { }// код... \ No newline at end of file diff --git a/images.yml b/images.yml index 357c267d0..84701c367 100644 --- a/images.yml +++ b/images.yml @@ -119,7 +119,7 @@ try-catch-flow.svg: 'try {': '' '': '' '}': '' - // code...: '' + // code...: '// код...' statusbarButtonGlyphs.svg: '!': '' From e5731a7bd1c27701c4f4ea73afee5231a746875e Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 00:54:52 +0200 Subject: [PATCH 09/17] Task name translation --- .../1-try-catch/1-finally-or-code-after/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index 1584bd278..9decf8d54 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -2,7 +2,7 @@ importance: 5 --- -# Finally or just the code? +# Finally чи просто код? Порівняй два фрагменти коду. From 7113dd36fe35718db882fccc49d2146d2b008999 Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 01:07:30 +0200 Subject: [PATCH 10/17] Typo fixes --- .../1-try-catch/1-finally-or-code-after/solution.md | 1 - .../1-try-catch/1-finally-or-code-after/task.md | 10 +++++----- 1-js/10-error-handling/1-try-catch/article.md | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index 51272598d..f989bfc5c 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -21,7 +21,6 @@ function f() { f(); // очищення! ``` -...Or when there's a `throw`, like here: ...Або якщо є `throw`: ```js run diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index 9decf8d54..9866c75d0 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -4,9 +4,9 @@ importance: 5 # Finally чи просто код? -Порівняй два фрагменти коду. +Порівняйте два фрагменти коду. -1. В першому використовується `finally` для виконання коду `try...catch`: +1. В першому використовується `finally` для виконання коду після `try...catch`: ```js try { @@ -19,7 +19,7 @@ importance: 5 */!* } ``` -2. В другому код очищення відбувається одразу після `try...catch`: +2. В другому коді очищення відбувається одразу після `try...catch`: ```js try { @@ -33,6 +33,6 @@ importance: 5 */!* ``` -Очищення ресурсів потрібно виконати після роботи не залежно від чи буде помилка. +Очищення ресурсів потрібно виконати після роботи не залежно від наявності помилки. -Які переваги використання `finally` чи обидва фрагменти коду однакові? Якщо різниця є -- наведіть приклади використання. +Які переваги використання `finally`, чи обидва фрагменти коду однакові? Якщо різниця є -- наведіть приклади використання. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 5fb310c8a..07ac5b654 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -561,13 +561,13 @@ function func() { } } -alert( func() ); // спочатку спрацює alert з finally, а потім в цьому рядку +alert( func() ); // спочатку спрацює alert з finally, а потім код в цьому рядку ``` ```` ````smart header="`try...finally`" -Конструкція `try...finally` може не мати `catch` частини, що також може стати у нагоді. Така конфігурація може бути використана, коли ми хочемо перехоплювати помилку, але потрібно завершити розпочаті задачі. +Конструкція `try...finally` може не мати `catch` частини, що також може стати у нагоді. Така конфігурація може бути використана, коли ми не хочемо перехоплювати помилку, але потрібно завершити розпочаті задачі. ```js function func() { @@ -590,9 +590,9 @@ function func() { Припустимо, через помилку програміста виключення трапилося поза блоком `try...catch` і призвело до припинення роботи скрипту. -Як ми можемо вчинити в такому випадку? Ми можемо логувати помилку, виводити повідомлення користувачу (переважно, користувачі не повинні бачити повідомлення про помилки) тощо. +Як нам вчинити в такому випадку? Ми можемо логувати помилку, виводити повідомлення користувачу (переважно, користувачі не повинні бачити повідомлення про помилки) тощо. -Специфікація не згадує таку можливість, але оточення, зазвичай, надають таку можливість для зручності. Наприклад, Node.js дозволяє викликати [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) для цього. В браузері можна присвоїти функцію спеціальній властивості [window.onerror](mdn:api/GlobalEventHandlers/onerror), що виконається, коли виникне помилка. +Специфікація не згадує таку можливість, але оточення, зазвичай, надають таку функцію для зручності. Наприклад, Node.js дозволяє викликати [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) для цього. В браузері можна присвоїти функцію спеціальній властивості [window.onerror](mdn:api/GlobalEventHandlers/onerror), що виконається, коли виникне помилка. Синтаксис: @@ -634,7 +634,7 @@ window.onerror = function(message, url, line, col, error) { Глобальний обробник `window.onerror` не передбачений для відновлювання роботи скрипту, а тільки відправлення повідомлення про помилку розробникам. -Для логування помилок в таких випадках існують спеціальні веб-сервіси: чи . +Для логування помилок в таких випадках існують спеціальні вебсервіси: чи . Вони працюють наступним чином: From de26d2fb0551d2dc0993f87e2d15c1193ea36375 Mon Sep 17 00:00:00 2001 From: purusah Date: Sun, 5 Dec 2021 01:13:12 +0200 Subject: [PATCH 11/17] More typo fixes --- 1-js/10-error-handling/1-try-catch/article.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 07ac5b654..5a0f40102 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -308,7 +308,7 @@ try { У такому разі відсутність властивості `name` є помилкою, оскільки користувачам потрібна інформація з цього поля. -Тож давайте викинемо її: +Тож викиньмо її: ```js run let json = '{ "age": 30 }'; // неповні дані @@ -330,7 +330,7 @@ try { } ``` -У рядку `(*)` оператор `throw` генерує `SyntaxError` із заданим значення поля `message`, таким же чином це зробив би JavaScript. Виконання коду в блоці `try` одразу припиняється і контроль передається в `catch`. +У рядку `(*)` оператор `throw` генерує `SyntaxError` із заданим значенням поля `message`, таким же чином це зробив би JavaScript. Виконання коду в блоці `try` одразу припиняється і контроль передається в `catch`. Тепер в блоці `catch` обробляються всі види помилок: від `JSON.parse` та інших випадків. @@ -355,7 +355,7 @@ try { Звичайно таке можливо! Програмісти теж помиляються. Навіть програми з відкритим кодом, що використовуються десятиріччями можуть раптово виявитися вразливими. -В нашому прикладі `try...catch` використовується для перехоплення помилок, що виникають у разі неповних даних. Але `catch` перехоплює *всі* типи помилок, що виникають в `try`. Тут виникає непередбачувана помилка, але все одно в в повідомленні виводиться `"JSON Error"`. Це неправильна поведінка, що ускладнює налагодження. +В нашому прикладі `try...catch` використовується для перехоплення помилок, що виникають у разі неповних даних. Але `catch` перехоплює *всі* типи помилок, що виникають в `try`. Тут виникає непередбачувана помилка, але все одно в повідомленні виводиться `"JSON Error"`. Це неправильна поведінка, що ускладнює налагодження. Щоб уникати таких проблем, ми можемо використовувати підхід "повторного викидання помилок". Правило просте: @@ -414,7 +414,7 @@ try { } ``` -Помилка, що виникає в рядку `(*)`, не проходить перевірку в `catch` блоці і повторно викидається. Виключення, після повторної генерації, може знову бути перехопленим конструкцією `try...catch` (якщо вона існує) або призведе до аварійного припинення роботи скрипту. +Помилка, що виникає в рядку `(*)`, не проходить перевірку в `catch` блоці й повторно викидається. Виключення, після повторної генерації, може знову бути перехопленим конструкцією `try...catch` (якщо вона існує) або призведе до аварійного припинення роботи скрипту. Така поведінка `catch` блоку дає змогу перехоплювати тільки помилки, для яких передбачено правила обробки та "пропускати" решту типів помилок. @@ -567,7 +567,7 @@ alert( func() ); // спочатку спрацює alert з finally, а пот ````smart header="`try...finally`" -Конструкція `try...finally` може не мати `catch` частини, що також може стати у нагоді. Така конфігурація може бути використана, коли ми не хочемо перехоплювати помилку, але потрібно завершити розпочаті задачі. +Конструкція `try...finally` може не мати `catch` частини, що також може стати у пригоді. Така конфігурація може бути використана, коли ми не хочемо перехоплювати помилку, але потрібно завершити розпочаті задачі. ```js function func() { @@ -665,7 +665,7 @@ try { Об’єкт помилки має наступні властивості: - `message` -- розбірливе повідомлення про помилку. - `name` -- рядок з іменем помилки (назва конструктора помилки). -- `stack` (нестандартна, але широко-підтримувана) -- стек викликів на момент створення помилки. +- `stack` (нестандартна, але широко підтримувана) -- стек викликів на момент створення помилки. Ми можемо пропустити отримання об’єкту помилки, якщо використати `catch {` замість `catch (err) {`. From acdc7a0fe8bfff534f95ba9349ee75826b3bc0ed Mon Sep 17 00:00:00 2001 From: purusah Date: Mon, 6 Dec 2021 22:32:45 +0200 Subject: [PATCH 12/17] Added review fixes --- .../1-finally-or-code-after/solution.md | 4 ++-- .../1-try-catch/1-finally-or-code-after/task.md | 2 +- 1-js/10-error-handling/1-try-catch/article.md | 16 +++++++--------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index f989bfc5c..f9d02566c 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -1,8 +1,8 @@ Різниця стає очевидною, якщо ми подивимося на код всередині функції. -Поведінка відрізняється, якщо код може раптово вийти з `try...catch`. +Поведінка відрізнятиметься, якщо код «раптово вийде» з блоку `try...catch`. -Наприклад, якщо є `return` всередині `try...catch`. Блок `finally` спрацює для "будь-якого" виходу з `try...catch`, навіть за допомогою `return`. Одразу після виходу `try...catch`, але перед передачею контролю коду, що викликав. +Наприклад, якщо всередині `try...catch` є `return`. Блок `finally` спрацює для "будь-якого" виходу з `try...catch`, навіть за допомогою `return` -- одразу після виходу з блоку `try...catch`, але перед передачею контролю кодові, що викликав цю функцію. ```js run function f() { diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index 9866c75d0..5528bc8d4 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -35,4 +35,4 @@ importance: 5 Очищення ресурсів потрібно виконати після роботи не залежно від наявності помилки. -Які переваги використання `finally`, чи обидва фрагменти коду однакові? Якщо різниця є -- наведіть приклади використання. +Чи є якійсь переваги використання `finally`, чи обидва фрагменти коду однакові? Якщо є різниця -- наведіть приклади використання. \ No newline at end of file diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 5a0f40102..969e0f5d1 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,6 +1,6 @@ # Робота з помилками, "try...catch" -На скільки чудовими програмістами ми б не були, але часом трапляється, що в роботі наших скрипів можуть виникати виключні ситуації. Вони виникають через наші помилки, непередбачувані вхідні дані від користувачів, неправильні відповіді від сервера або з тисяч інших причин. +Якими чудовими програмістами ми б не були, часом трапляється, що в наших скриптах виникають помилки. Вони можуть виникнути через нашу неуважність, непередбачувані вхідні дані від користувачів, неправильні відповіді від сервера або з тисяч інших причин. Якщо виникають помилки, то скрипти, зазвичай, "помирають" (раптово припиняють роботу) та виводять інформацію про помилку в консоль. @@ -25,8 +25,8 @@ try { Це працює наступним чином: 1. В першу чергу виконується код в блоці `try {...}`. -2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця блоку `try` та продовжується поза `catch` блоком. -3. Якщо виникає помилка, тоді виконання в `try` припиняється і виконання коду продовжується з початку `catch (err)` блоку. Змінна `err` (можна обрати інше ім’я) буде містити об’єкт помилки з додатковою інформацією. +2. Якщо не виникає помилок, то блок `catch (err)` ігнорується: виконання досягає кінця блоку `try` та продовжується поза блоком `catch`. +3. Якщо виникає помилка, тоді виконання в `try` припиняється і виконання коду продовжується з початку блоку `catch (err)`. Змінна `err` (можна обрати будь-яке ім’я) буде містити об’єкт помилки з додатковою інформацією. ![](try-catch-flow.svg) @@ -39,11 +39,11 @@ try { ```js run try { - alert('Початок try блоку'); // *!*(1) <--*/!* + alert('Початок блоку try'); // *!*(1) <--*/!* // ...код без помилок - alert('Кінець try блоку'); // *!*(2) <--*/!* + alert('Кінець блоку try'); // *!*(2) <--*/!* } catch (err) { @@ -56,13 +56,13 @@ try { ```js run try { - alert('Початок try блоку'); // *!*(1) <--*/!* + alert('Початок блоку try'); // *!*(1) <--*/!* *!* lalala; // помилка, змінна не визначена! */!* - alert('Кінець try блоку (не буде виконано)'); // (2) + alert('Кінець блоку try (не буде виконано)'); // (2) } catch (err) { @@ -141,8 +141,6 @@ try { Існують інші властивості, що доступні в більшості оточень. Одна з найуживаніших та часто підтримується: `stack` -: Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes. - : Поточний стек викликів: рядок з інформацією про послідовність вкладених викликів, що призвели до помилки. Використовується для налагодження. Наприклад: From 180fd3b4aa8b1af36306179cb8288cf5a13684ae Mon Sep 17 00:00:00 2001 From: purusah Date: Mon, 6 Dec 2021 22:35:00 +0200 Subject: [PATCH 13/17] Adjust word order to general style --- 1-js/10-error-handling/1-try-catch/article.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 969e0f5d1..6a6f8b611 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -30,7 +30,7 @@ try { ![](try-catch-flow.svg) -Отже, помилка всередині `try {...}` блоку не призводить до раптового припинення роботи скрипту - ми отримуємо можливість обробити її в `catch`. +Отже, помилка всередині блоку `try {...}` не призводить до раптового припинення роботи скрипту - ми отримуємо можливість обробити її в `catch`. Подивімося на декілька прикладів. @@ -227,7 +227,7 @@ try { } ``` -У цьому разі `catch` блок використано тільки для виведення повідомлення про помилку, але може бути використаним іншим чином: відправити новий запит, запропонувати користувачі інші опції, відправити інформацію про помилку для логування та ін. Будь-який спосіб використання краще, ніж раптове припинення роботи. +У цьому разі блок `catch` використано тільки для виведення повідомлення про помилку, але може бути використаним іншим чином: відправити новий запит, запропонувати користувачі інші опції, відправити інформацію про помилку для логування та ін. Будь-який спосіб використання краще, ніж раптове припинення роботи. ## Створення та викидання власних типів помилок @@ -412,9 +412,9 @@ try { } ``` -Помилка, що виникає в рядку `(*)`, не проходить перевірку в `catch` блоці й повторно викидається. Виключення, після повторної генерації, може знову бути перехопленим конструкцією `try...catch` (якщо вона існує) або призведе до аварійного припинення роботи скрипту. +Помилка, що виникає в рядку `(*)`, не проходить перевірку в блоці `catch` й повторно викидається. Виключення, після повторної генерації, може знову бути перехопленим конструкцією `try...catch` (якщо вона існує) або призведе до аварійного припинення роботи скрипту. -Така поведінка `catch` блоку дає змогу перехоплювати тільки помилки, для яких передбачено правила обробки та "пропускати" решту типів помилок. +Така поведінка блоку `catch` дає змогу перехоплювати тільки помилки, для яких передбачено правила обробки та "пропускати" решту типів помилок. Приклад нижче демонструє, як реалізувати перехоплення таких помилок ще одним рівнем `try...catch`: From e267ed2081fe982dbe055e799550fd541283ef5c Mon Sep 17 00:00:00 2001 From: Taras Date: Tue, 7 Dec 2021 11:40:44 +0200 Subject: [PATCH 14/17] Small fixes --- 1-js/10-error-handling/1-try-catch/article.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 6a6f8b611..fd16f4f6e 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -661,14 +661,15 @@ try { Також ми можемо пропустити секцію `catch` чи `finally`, тому скорочені конструкції `try...catch` та `try...finally` теж валідні. Об’єкт помилки має наступні властивості: + - `message` -- розбірливе повідомлення про помилку. - `name` -- рядок з іменем помилки (назва конструктора помилки). - `stack` (нестандартна, але широко підтримувана) -- стек викликів на момент створення помилки. Ми можемо пропустити отримання об’єкту помилки, якщо використати `catch {` замість `catch (err) {`. -Також ми можемо генерувати власні помилки за допомогою оператору `throw`. Технічно, будь-що можна передати аргументом в `throw`, але, зазвичай, використовується об'єкт успадкований від вбудованого класу `Error`. Більше про розширення помилок в наступному розділі. +Також ми можемо генерувати власні помилки за допомогою оператору `throw`. Технічно, будь-що можна передати аргументом в `throw`, але, зазвичай, використовується об’єкт, успадкований від вбудованого класу `Error`. Детальніше про розширення помилок в наступному розділі. *Повторне викидання* -- важливий шаблон в роботі з помилками: переважно блок `catch` знає як обробляти помилки певного типу, тому він повинен знову викидати невідомі типи помилок. -Навіть, якщо ми не використовуємо `try...catch`, більшість оточень дозволяють встановити "глобальний" обробник помилок. В браузерах це `window.onerror`. +Навіть, якщо ми не використовуємо `try...catch`, більшість середовищ дозволяють встановити "глобальний" обробник помилок. В браузерах це `window.onerror`. From 34d6e44c832e19e3e7e3b91c97d7c5731be1cdbf Mon Sep 17 00:00:00 2001 From: Vladyslav Bohaichuk Date: Sun, 26 Dec 2021 21:15:00 +0200 Subject: [PATCH 15/17] Translate Export and Import Export and Import --- 1-js/13-modules/02-import-export/article.md | 304 ++++++++++---------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 10e47820f..75bf517e1 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -1,23 +1,23 @@ -# Export and Import +# Експорт та імпорт -Export and import directives have several syntax variants. +Директиви експорту та імпорту мають декілька варіантів синтаксису. -In the previous article we saw a simple use, now let's explore more examples. +В попередній статті ми вже бачили спосіб простого використання, тому давайте розглянемо ще декілька прикладів. -## Export before declarations +## Експорт перед оголошенням -We can label any declaration as exported by placing `export` before it, be it a variable, function or a class. +Будь-яке оголошення змінної, функції чи класу можна позначати попереду оператором `export`. -For instance, here all exports are valid: +Наприклад, всі наступні експорти валідні: ```js -// export an array -*!*export*/!* let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +// експорт масиву +*!*export*/!* let months = ['Січ', 'Лют', 'Бер','Квіт', 'Серп', 'Вер', 'Жов', 'Лист', 'Груд']; -// export a constant +// експорт константи *!*export*/!* const MODULES_BECAME_STANDARD_YEAR = 2015; -// export a class +// експорт класу *!*export*/!* class User { constructor(name) { this.name = name; @@ -25,47 +25,47 @@ For instance, here all exports are valid: } ``` -````smart header="No semicolons after export class/function" -Please note that `export` before a class or a function does not make it a [function expression](info:function-expressions). It's still a function declaration, albeit exported. +````smart header="Не потрібно ставити крапку з комою після експорту класу чи функції" +Зверніть увагу, `export` перед класом чи функцією не перетворює її в [функціональний вираз](info:function-expressions). Це все ще оголошення функції, хоч і експортованої. -Most JavaScript style guides don't recommend semicolons after function and class declarations. +Більшість стилів JavaScript коду не рекомендують ставити крапку з комою після оголошення функції та класу. -That's why there's no need for a semicolon at the end of `export class` and `export function`: +Тому не потрібно додавати крапку з комою в кінці `export class` та `export function`: ```js export function sayHi(user) { - alert(`Hello, ${user}!`); -} *!* // no ; at the end */!* + alert(`Привіт, ${user}!`); +} *!* // знак ; відсутній вкінці */!* ``` ```` -## Export apart from declarations +## Експорт поза оголошенням -Also, we can put `export` separately. +Також `export` можна використовувати окремо. -Here we first declare, and then export: +В прикладі ми спочатку оголошуємо функцію, а потім експортуємо: -```js +```js // 📁 say.js function sayHi(user) { - alert(`Hello, ${user}!`); + alert(`Привіт, ${user}!`); } function sayBye(user) { - alert(`Bye, ${user}!`); + alert(`Бувай, ${user}!`); } *!* -export {sayHi, sayBye}; // a list of exported variables +export {sayHi, sayBye}; // список експортованих змінних */!* ``` -...Or, technically we could put `export` above functions as well. +...Чи, технічно, ми можемо використати `export` вище оголошення функції. -## Import * +## Імпорт * -Usually, we put a list of what to import in curly braces `import {...}`, like this: +Зазвичай, список того, що потрібно імпортувати розташовують у фігурні дужки `import {...}`, як у прикладі: ```js // 📁 main.js @@ -73,11 +73,11 @@ Usually, we put a list of what to import in curly braces `import {...}`, like th import {sayHi, sayBye} from './say.js'; */!* -sayHi('John'); // Hello, John! -sayBye('John'); // Bye, John! +sayHi('Іван'); // Привіт, Іван! +sayBye('Іван'); // Бувай, Іван! ``` -But if there's a lot to import, we can import everything as an object using `import * as `, for instance: +Якщо потрібно імпортувати дуже багато сутностей, ми можемо імпортувати все, як об’єкт з використанням `import * as `, наприклад: ```js // 📁 main.js @@ -85,17 +85,17 @@ But if there's a lot to import, we can import everything as an object using `imp import * as say from './say.js'; */!* -say.sayHi('John'); -say.sayBye('John'); +say.sayHi('Іван'); +say.sayBye('Іван'); ``` -At first sight, "import everything" seems such a cool thing, short to write, why should we ever explicitly list what we need to import? +З першого погляду, "імпортувати все" виглядає цікавим та зручним у використанні, тоді навіщо нам явно виписувати список того, що потрібно імпортувати? -Well, there are few reasons. +На це є декілька причин. -1. Modern build tools ([webpack](http://webpack.github.io) and others) bundle modules together and optimize them to speedup loading and remove unused stuff. +1. Сучасні інструменти збирання ([webpack](http://webpack.github.io) та інші) об’єднують модулі разом, оптимізують їх для пришвидшення завантаження та видаляють невикористані частини. - Let's say, we added a 3rd-party library `say.js` to our project with many functions: + Скажімо, ми додали сторонню бібліотеку, з багатьма функціями, `say.js` до нашого проекту: ```js // 📁 say.js export function sayHi() { ... } @@ -103,21 +103,21 @@ Well, there are few reasons. export function becomeSilent() { ... } ``` - Now if we only use one of `say.js` functions in our project: + Припустимо, ми використовуємо тільки одну функцію з `say.js` в нашому проекті: ```js // 📁 main.js import {sayHi} from './say.js'; ``` - ...Then the optimizer will see that and remove the other functions from the bundled code, thus making the build smaller. That is called "tree-shaking". + ...Тоді оптимізатор побачить це та видалить інші функції із об’єднаного коду, що робить зібраний проект меншим. Так званий "tree-shaking". -2. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. -3. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. +2. Явний список того, що потрібно імпортувати дає коротші імена: `sayHi()` замість `say.sayHi()`. +3. Явний список того, що потрібно імпортувати дає краще розуміння структури коду: що використано та в якому місці. Також дозволяє підтримувати та рефакторити код легше. -## Import "as" +## Імпорт "as" -We can also use `as` to import under different names. +Для імпорту під іншим іменем можна використовувати `as`. -For instance, let's import `sayHi` into the local variable `hi` for brevity, and import `sayBye` as `bye`: +Наприклад, для спрощення імпортуймо `sayHi` в локальну змінну `hi` та `sayBye` як `bye`: ```js // 📁 main.js @@ -125,15 +125,15 @@ For instance, let's import `sayHi` into the local variable `hi` for brevity, and import {sayHi as hi, sayBye as bye} from './say.js'; */!* -hi('John'); // Hello, John! -bye('John'); // Bye, John! +hi('Іван'); // Привіт, Іван! +bye('Іван'); // Бувай, Іван! ``` -## Export "as" +## Експорт "as" -The similar syntax exists for `export`. +Подібний синтаксис існує і для `export`. -Let's export functions as `hi` and `bye`: +Експортуймо функцію як `hi` та `bye`: ```js // 📁 say.js @@ -141,107 +141,107 @@ Let's export functions as `hi` and `bye`: export {sayHi as hi, sayBye as bye}; ``` -Now `hi` and `bye` are official names for outsiders, to be used in imports: +Тепер `hi` та `bye` будуть використовуватися зовнішніми модулями при імпорті: ```js // 📁 main.js import * as say from './say.js'; -say.*!*hi*/!*('John'); // Hello, John! -say.*!*bye*/!*('John'); // Bye, John! +say.*!*hi*/!*('Іван'); // Привіт, Іван! +say.*!*bye*/!*('Іван'); // Бувай, Іван! ``` -## Export default +## Експорт за замовчуванням -In practice, there are mainly two kinds of modules. +На практиці існує два головних типи модулів. -1. Modules that contain a library, pack of functions, like `say.js` above. -2. Modules that declare a single entity, e.g. a module `user.js` exports only `class User`. +1. Модулі, що містять бібліотеку -- набір функцій, як `say.js` вище. +2. Модулі, що визначають єдину сутність, тобто модуль `user.js` експортує тільки `class User`. -Mostly, the second approach is preferred, so that every "thing" resides in its own module. +Переважно, надавати перевагу потрібно другому підходу, таким чином усі "сутності" знаходяться у власних модулях. -Naturally, that requires a lot of files, as everything wants its own module, but that's not a problem at all. Actually, code navigation becomes easier if files are well-named and structured into folders. +Очевидно, що це вимагає великої кількості файлів, щоб усе мало власні модулі, але це зовсім не проблема. Насправді, навігація в коді полегшується, якщо всі файли мають вдалу назву та структуровані в теках. -Modules provide a special `export default` ("the default export") syntax to make the "one thing per module" way look better. +Модулі використовують спеціальний синтаксис `export default` ("експорт за замовчуванням") для створення єдиності сутності та полегшення доступності. -Put `export default` before the entity to export: +Якщо сутність потрібно експортувати -- попереду потрібно поставити `export default`: ```js // 📁 user.js -export *!*default*/!* class User { // just add "default" +export *!*default*/!* class User { // потрібно додати лише "default" constructor(name) { this.name = name; } } ``` -There may be only one `export default` per file. +В кожному файлі може бути тільки одне використання `export default`. -...And then import it without curly braces: +...А потім потрібно виконати імпорт без фігурних дужок: ```js // 📁 main.js -import *!*User*/!* from './user.js'; // not {User}, just User +import *!*User*/!* from './user.js'; // не {User}, а просто User new User('John'); ``` -Imports without curly braces look nicer. A common mistake when starting to use modules is to forget curly braces at all. So, remember, `import` needs curly braces for named exports and doesn't need them for the default one. +Імпорти без фігурних дужок виглядають краще. Коли починають використовувати модулі, поширеною помилкою є невикористання фігурних дужок взагалі. Отже, `import` потребує фігурних дужок для іменованих імпортів та не потребує, якщо це імпорт за замовчуванням. -| Named export | Default export | +| Іменований експорт | Експорт за замовчуванням | |--------------|----------------| | `export class User {...}` | `export default class User {...}` | | `import {User} from ...` | `import User from ...`| -Technically, we may have both default and named exports in a single module, but in practice people usually don't mix them. A module has either named exports or the default one. +Технічно, ми можемо використовувати іменовані експорти та експорти за замовчуванням в одному модулі, але, на практиці, їх не прийнято змішувати. Модулі повинні мати або іменований експорт, або за замовчуванням. -As there may be at most one default export per file, the exported entity may have no name. +Оскільки, тільки одна сутність може бути експортованою за замовчування, вона може не мати імені. -For instance, these are all perfectly valid default exports: +В прикладі використано правильні експорти за замовчування: ```js -export default class { // no class name +export default class { // відсутнє ім’я класу constructor() { ... } } ``` ```js -export default function(user) { // no function name - alert(`Hello, ${user}!`); +export default function(user) { // відсутнє ім’я функції + alert(`Привіт, ${user}!`); } ``` ```js -// export a single value, without making a variable +// експортовано єдину змінну без оголошення export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; ``` -Not giving a name is fine, because there is only one `export default` per file, so `import` without curly braces knows what to import. +Відсутність імені є абсолютно нормальним, бо може бути тільки одне використання `export default` у файлі. Таким чином `import` без фігурних дужок знає, що імпортувати. -Without `default`, such an export would give an error: +Такий експорт без `default` згенерує помилку: ```js -export class { // Error! (non-default export needs a name) +export class { // Помилка! (експорт за замовчування потребує імені) constructor() {} } -``` +``` -### The "default" name +### Ім’я "default" -In some situations the `default` keyword is used to reference the default export. +В деяких ситуаціях ключове слово `default` використовують для позначення імпорту за замовчування. -For example, to export a function separately from its definition: +Наприклад, для експорту функції окремо від її оголошення: ```js function sayHi(user) { - alert(`Hello, ${user}!`); + alert(`Привіт, ${user}!`); } -// same as if we added "export default" before the function +// те ж саме, якби ми додали "export default" перед оголошенням функції export {sayHi as default}; ``` -Or, another situation, let's say a module `user.js` exports one main "default" thing, and a few named ones (rarely the case, but it happens): +Чи, в іншій ситуації, скажімо модуль `user.js` експортує єдину "головну" сутність та ще декілька іменованих (рідко, але таке трапляється): ```js // 📁 user.js @@ -252,51 +252,51 @@ export default class User { } export function sayHi(user) { - alert(`Hello, ${user}!`); + alert(`Привіт, ${user}!`); } ``` -Here's how to import the default export along with a named one: +Для імпорту типової сутності та декількох іменованих потрібно: ```js // 📁 main.js import {*!*default as User*/!*, sayHi} from './user.js'; -new User('John'); +new User('Іван'); ``` -And, finally, if importing everything `*` as an object, then the `default` property is exactly the default export: +Урешті-решт, якщо імпортувати всі `*` як об'єкт, тоді властивість `default` матиме значення імпорту за замовчуванням: ```js // 📁 main.js import * as user from './user.js'; -let User = user.default; // the default export -new User('John'); +let User = user.default; // імпорт за замовчуванням +new User('Іван'); ``` -### A word against default exports +### Аргументи проти імпортів за замовчуванням -Named exports are explicit. They exactly name what they import, so we have that information from them; that's a good thing. +Іменовані імпорти є явними. Нам потрібно точно перелічити все, що імпортуємо - це є перевагою. -Named exports force us to use exactly the right name to import: +Іменовані експорти змушують нас використовувати точне ім’я сутності для імпорту: ```js import {User} from './user.js'; -// import {MyUser} won't work, the name must be {User} +// import {MyUser} не спрацює, оскільки ім’я повинно бути {User} ``` -...While for a default export, we always choose the name when importing: +...В той час, як для імпорту за замовчуванням нам завжди потрібно обрати ім’я: ```js -import User from './user.js'; // works -import MyUser from './user.js'; // works too -// could be import Anything... and it'll still work +import User from './user.js'; // спрацює +import MyUser from './user.js'; // спрацює теж +// можна навіть import Anything... і це все одно ще спрацює ``` -So team members may use different names to import the same thing, and that's not good. +Таким чином різні члени команд можуть використовувати різні імена для імпорту однакових сутностей і це не дуже добре. -Usually, to avoid that and keep the code consistent, there's a rule that imported variables should correspond to file names, e.g: +Зазвичай, щоб уникати цього і тримати код узгодженим, існує правило - імпортована змінна повинна мати ім’я, що відповідає імені файлу: ```js import User from './user.js'; @@ -305,28 +305,28 @@ import func from '/path/to/func.js'; ... ``` -Still, some teams consider it a serious drawback of default exports. So they prefer to always use named exports. Even if only a single thing is exported, it's still exported under a name, without `default`. +А втім, деякі команди все ще вважають це серйозним недоліком експортів за замовчуванням. Тому вони надають перевагу використанню іменованих експортів. Навіть якщо експортують одну сутність, її все одно експортують з іменем, без `default`. -That also makes re-export (see below) a little bit easier. +Це також дозволяє полегшити повторний експорт (наступний розділ). -## Re-export +## Реекспорт -"Re-export" syntax `export ... from ...` allows to import things and immediately export them (possibly under another name), like this: +Синтаксис "реекспорту" `export ... from ...` дозволяє одночасно імпортувати сутності та експортувати (можливо під іншими іменем) як тут: ```js -export {sayHi} from './say.js'; // re-export sayHi +export {sayHi} from './say.js'; // реекспорт sayHi -export {default as User} from './user.js'; // re-export default +export {default as User} from './user.js'; // реекспорт default ``` -Why would that be needed? Let's see a practical use case. +Навіщо нам це може знадобитися? Розглянемо практичний спосіб використання. -Imagine, we're writing a "package": a folder with a lot of modules, with some of the functionality exported outside (tools like NPM allow us to publish and distribute such packages, but we don't have to use them), and many modules are just "helpers", for internal use in other package modules. +Уявімо, що нам потрібно написати "пакунок": директорію з багатьма модулями, що експортує певний функціонал (інструменти як NPM дозволяють публікувати та розповсюджувати такі пакунки, але ми не зобов’язані їх використовувати). Багато таких пакунків використовуються в ролі допоміжних, для внутрішнього використання всередині інших модулів. -The file structure could be like this: +Файлова структура може мати такий вигляд: ``` auth/ - index.js + index.js user.js helpers.js tests/ @@ -337,56 +337,56 @@ auth/ ... ``` -We'd like to expose the package functionality via a single entry point. +Для доступу до функціоналу пакунку ззовні ми б хотіли створити єдину точку входу. -In other words, a person who would like to use our package, should import only from the "main file" `auth/index.js`. +Інакше кажучи, користувачі для використання функціоналу нашого пакунку повинні імпортувати тільки "головний файл" `auth/index.js`. -Like this: +Наприклад: ```js import {login, logout} from 'auth/index.js' ``` -The "main file", `auth/index.js` exports all the functionality that we'd like to provide in our package. +"Головний файл" `auth/index.js` експортує весь функціонал, що ми б хотіли надати з цим пакунком. -The idea is that outsiders, other programmers who use our package, should not meddle with its internal structure, search for files inside our package folder. We export only what's necessary in `auth/index.js` and keep the rest hidden from prying eyes. +Ідея полягає в тому, щоб інші програмісти, хто буде використовувати наш пакунок, не матимуть змогу втрутитися у внутрішню структуру. Ми експортуємо тільки те, що необхідно з `auth/index.js` та тримаємо решту прихованим від допитливих очей. -As the actual exported functionality is scattered among the package, we can import it into `auth/index.js` and export from it: +Оскільки, функціональність, до якої ми хочемо надати доступ, може знаходитися в різних частинах пакунку, ми можемо імпортувати її та повторно експортувати в `auth/index.js`: ```js // 📁 auth/index.js -// import login/logout and immediately export them +// імпортуємо login/logout та одразу експортуємо їх import {login, logout} from './helpers.js'; export {login, logout}; -// import default as User and export it +// імпортуємо User за замовчуванням та експортуємо його import User from './user.js'; export {User}; ... ``` -Now users of our package can `import {login} from "auth/index.js"`. +Тепер користувачі нашого пакунку зможуть виконати `import {login} from "auth/index.js"`. -The syntax `export ... from ...` is just a shorter notation for such import-export: +Синтаксис `export ... from ...` - просто скорочений запис для імпорту-експорту: ```js // 📁 auth/index.js -// re-export login/logout +// реекспорт login/logout export {login, logout} from './helpers.js'; -// re-export the default export as User +// реекспорт за замовчуванням під іменем User export {default as User} from './user.js'; ... ``` -The notable difference of `export ... from` compared to `import/export` is that re-exported modules aren't available in the current file. So inside the above example of `auth/index.js` we can't use re-exported `login/logout` functions. +Суттєвою різницею між `export ... from` та `import/export` є недоступність реекспортованих модулів всередині поточного файлу. Тому в прикладі вище всередині файлу `auth/index.js` ми не зможемо використати реекспортовані функції `login/logout`. -### Re-exporting the default export +### Реекспорт експорту за замовчуванням -The default export needs separate handling when re-exporting. +Експорт за замовчуванням для реекспорту потребує спеціальної обробки. -Let's say we have `user.js` with the `export default class User` and would like to re-export it: +Скажімо, у нас є `user.js` з якого ми хочемо реекспортувати клас `User`: ```js // 📁 user.js @@ -395,71 +395,71 @@ export default class User { } ``` -We can come across two problems with it: +У нас може виникнути дві проблеми: -1. `export User from './user.js'` won't work. That would lead to a syntax error. +1. `export User from './user.js'` не спрацює. Це призведе до синтаксичної помилки. - To re-export the default export, we have to write `export {default as User}`, as in the example above. + Для реекспорту за замовчуванням, нам потрібно використати `export {default as User}`, як в прикладі вище. -2. `export * from './user.js'` re-exports only named exports, but ignores the default one. +2. `export * from './user.js'` реекспортує тільки іменовані експорти і проігнорує ті, що за замовчуванням. - If we'd like to re-export both named and the default export, then two statements are needed: + Якщо ми хочемо реекспортувати як іменовані експорти, так і експорти за замовчуванням тоді нам потрібні дві інструкції: ```js - export * from './user.js'; // to re-export named exports - export {default} from './user.js'; // to re-export the default export + export * from './user.js'; // для реекспорту іменованих експортів + export {default} from './user.js'; // для реекспорту експортів за замовчуванням ``` -Such oddities of re-exporting a default export are one of the reasons why some developers don't like default exports and prefer named ones. +Такі дивацтва для реекспорту експортів за замовчуванням є однією з причин чому деякі розробники недолюблюють експорти за замовчуванням та надають перевагу іменованим. -## Summary +## Підсумки -Here are all types of `export` that we covered in this and previous articles. +Ось всі типи `export`, що ми розглянули в цій та попередній частинах. -You can check yourself by reading them and recalling what they mean: +Щоб перевірити себе, ви можете прочитати та згадати, що вони означають: -- Before declaration of a class/function/..: +- Перед оголошенням класу/функції/..: - `export [default] class/function/variable ...` -- Standalone export: +- Окремий експорт: - `export {x [as y], ...}`. -- Re-export: +- Реекспорт: - `export {x [as y], ...} from "module"` - - `export * from "module"` (doesn't re-export default). - - `export {default [as y]} from "module"` (re-export default). + - `export * from "module"` (не реекспортує за замовчуванням). + - `export {default [as y]} from "module"` (реекспорт за замовчуванням). -Import: +Імпорт: -- Importing named exports: +- Імпорт іменованих експортів: - `import {x [as y], ...} from "module"` -- Importing the default export: +- Імпорт експортів за замовчуванням: - `import x from "module"` - `import {default as x} from "module"` -- Import all: +- Імпортування всього: - `import * as obj from "module"` -- Import the module (its code runs), but do not assign any of its exports to variables: +- Тільки імпорт модуля (буде виконано його код) без присвоєння в змінну: - `import "module"` -We can put `import/export` statements at the top or at the bottom of a script, that doesn't matter. +Інструкції `import/export` можуть бути розташовані як зверху, так і знизу в скрипті. -So, technically this code is fine: +Тому, технічно, це правильний код: ```js sayHi(); // ... -import {sayHi} from './say.js'; // import at the end of the file +import {sayHi} from './say.js'; // імпорт розташовано в кінці файлу ``` -In practice imports are usually at the start of the file, but that's only for more convenience. +На практиці, імпорти зазвичай розташовують на початку файлу, але це переважно для зручності. -**Please note that import/export statements don't work if inside `{...}`.** +**Зверніть увагу, що інструкції імпорту та експорту не спрацюють, якщо розташовані всередині `{...}`.** -A conditional import, like this, won't work: +Умовний імпорт, як в наступному прикладі, не спрацює: ```js if (something) { import {sayHi} from "./say.js"; // Error: import must be at top level } ``` -...But what if we really need to import something conditionally? Or at the right time? Like, load a module upon request, when it's really needed? +...Що робити, якщо нам потрібно щось імпортувати за певних умов? Або в певний час? Наприклад, завантажити модуль за запитом, коли він дійсно стане потрібним. -We'll see dynamic imports in the next article. +Динамічні імпорти буде розглянуто в наступній частині. From 18a0190425f1b7aa39de8c06660bb7e6f2d8b0d0 Mon Sep 17 00:00:00 2001 From: Taras Date: Mon, 27 Dec 2021 14:44:53 +0200 Subject: [PATCH 16/17] Apply suggestions from code review --- 1-js/13-modules/02-import-export/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 75bf517e1..993d71f41 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -151,7 +151,7 @@ say.*!*hi*/!*('Іван'); // Привіт, Іван! say.*!*bye*/!*('Іван'); // Бувай, Іван! ``` -## Експорт за замовчуванням +## Типовий експорт (export default) На практиці існує два головних типи модулів. @@ -188,7 +188,7 @@ new User('John'); Імпорти без фігурних дужок виглядають краще. Коли починають використовувати модулі, поширеною помилкою є невикористання фігурних дужок взагалі. Отже, `import` потребує фігурних дужок для іменованих імпортів та не потребує, якщо це імпорт за замовчуванням. -| Іменований експорт | Експорт за замовчуванням | +| Іменований експорт | Типовий експорт | |--------------|----------------| | `export class User {...}` | `export default class User {...}` | | `import {User} from ...` | `import User from ...`| From 0fe2e48ffcbed019f66bae57032de008833a19b2 Mon Sep 17 00:00:00 2001 From: Vladyslav Bohaichuk Date: Mon, 27 Dec 2021 20:37:51 +0200 Subject: [PATCH 17/17] Fix import-export default translation --- 1-js/13-modules/02-import-export/article.md | 50 ++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 993d71f41..8d4d31b95 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -151,7 +151,7 @@ say.*!*hi*/!*('Іван'); // Привіт, Іван! say.*!*bye*/!*('Іван'); // Бувай, Іван! ``` -## Типовий експорт (export default) +## Типовий експорт На практиці існує два головних типи модулів. @@ -162,7 +162,7 @@ say.*!*bye*/!*('Іван'); // Бувай, Іван! Очевидно, що це вимагає великої кількості файлів, щоб усе мало власні модулі, але це зовсім не проблема. Насправді, навігація в коді полегшується, якщо всі файли мають вдалу назву та структуровані в теках. -Модулі використовують спеціальний синтаксис `export default` ("експорт за замовчуванням") для створення єдиності сутності та полегшення доступності. +Модулі використовують спеціальний синтаксис `export default` ("типовий експорт") для створення єдиної сутності та полегшення доступності. Якщо сутність потрібно експортувати -- попереду потрібно поставити `export default`: @@ -186,18 +186,18 @@ import *!*User*/!* from './user.js'; // не {User}, а просто User new User('John'); ``` -Імпорти без фігурних дужок виглядають краще. Коли починають використовувати модулі, поширеною помилкою є невикористання фігурних дужок взагалі. Отже, `import` потребує фігурних дужок для іменованих імпортів та не потребує, якщо це імпорт за замовчуванням. +Імпорти без фігурних дужок виглядають краще. Коли починають використовувати модулі, поширеною помилкою є невикористання фігурних дужок взагалі. Отже, `import` потребує фігурних дужок для іменованих імпортів та не потребує, якщо це типовий імпорт. | Іменований експорт | Типовий експорт | |--------------|----------------| | `export class User {...}` | `export default class User {...}` | | `import {User} from ...` | `import User from ...`| -Технічно, ми можемо використовувати іменовані експорти та експорти за замовчуванням в одному модулі, але, на практиці, їх не прийнято змішувати. Модулі повинні мати або іменований експорт, або за замовчуванням. +Технічно, ми можемо використовувати іменовані та типові експорти в одному модулі, але, на практиці, їх не прийнято змішувати. Модулі повинні мати або іменований експорт, або типовий. -Оскільки, тільки одна сутність може бути експортованою за замовчування, вона може не мати імені. +Оскільки, тільки одна сутність може бути типово експортованою, вона може не мати імені. -В прикладі використано правильні експорти за замовчування: +В прикладі правильно використано типові експорти: ```js export default class { // відсутнє ім’я класу @@ -221,14 +221,14 @@ export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; Такий експорт без `default` згенерує помилку: ```js -export class { // Помилка! (експорт за замовчування потребує імені) +export class { // Помилка! (типовий експорт потребує імені) constructor() {} } ``` ### Ім’я "default" -В деяких ситуаціях ключове слово `default` використовують для позначення імпорту за замовчування. +В деяких ситуаціях ключове слово `default` використовують для позначення типового імпорту. Наприклад, для експорту функції окремо від її оголошення: @@ -265,17 +265,17 @@ import {*!*default as User*/!*, sayHi} from './user.js'; new User('Іван'); ``` -Урешті-решт, якщо імпортувати всі `*` як об'єкт, тоді властивість `default` матиме значення імпорту за замовчуванням: +Урешті-решт, якщо імпортувати всі `*` як об'єкт, тоді властивість `default` матиме значення типового імпорту: ```js // 📁 main.js import * as user from './user.js'; -let User = user.default; // імпорт за замовчуванням +let User = user.default; // типовий імпорт new User('Іван'); ``` -### Аргументи проти імпортів за замовчуванням +### Аргументи проти типових імпортів Іменовані імпорти є явними. Нам потрібно точно перелічити все, що імпортуємо - це є перевагою. @@ -286,7 +286,7 @@ import {User} from './user.js'; // import {MyUser} не спрацює, оскільки ім’я повинно бути {User} ``` -...В той час, як для імпорту за замовчуванням нам завжди потрібно обрати ім’я: +...В той час, як для типового імпорту нам завжди потрібно обрати ім’я: ```js import User from './user.js'; // спрацює @@ -305,7 +305,7 @@ import func from '/path/to/func.js'; ... ``` -А втім, деякі команди все ще вважають це серйозним недоліком експортів за замовчуванням. Тому вони надають перевагу використанню іменованих експортів. Навіть якщо експортують одну сутність, її все одно експортують з іменем, без `default`. +А втім, деякі команди все ще вважають це серйозним недоліком типових експортів. Тому вони надають перевагу використанню іменованих експортів. Навіть якщо експортують одну сутність, її все одно експортують з іменем, без `default`. Це також дозволяє полегшити повторний експорт (наступний розділ). @@ -360,7 +360,7 @@ import {login, logout} from 'auth/index.js' import {login, logout} from './helpers.js'; export {login, logout}; -// імпортуємо User за замовчуванням та експортуємо його +// типово імпортуємо User та експортуємо його import User from './user.js'; export {User}; ... @@ -375,16 +375,16 @@ export {User}; // реекспорт login/logout export {login, logout} from './helpers.js'; -// реекспорт за замовчуванням під іменем User +// реекспорт типового експорту під іменем User export {default as User} from './user.js'; ... ``` Суттєвою різницею між `export ... from` та `import/export` є недоступність реекспортованих модулів всередині поточного файлу. Тому в прикладі вище всередині файлу `auth/index.js` ми не зможемо використати реекспортовані функції `login/logout`. -### Реекспорт експорту за замовчуванням +### Реекспорт типового експорту -Експорт за замовчуванням для реекспорту потребує спеціальної обробки. +Для реекспорту типового експорту потрібна спеціальна обробка. Скажімо, у нас є `user.js` з якого ми хочемо реекспортувати клас `User`: @@ -399,17 +399,17 @@ export default class User { 1. `export User from './user.js'` не спрацює. Це призведе до синтаксичної помилки. - Для реекспорту за замовчуванням, нам потрібно використати `export {default as User}`, як в прикладі вище. + Для типового реекспорту нам потрібно використати `export {default as User}`, як в прикладі вище. -2. `export * from './user.js'` реекспортує тільки іменовані експорти і проігнорує ті, що за замовчуванням. +2. `export * from './user.js'` реекспортує тільки іменовані експорти і проігнорує типові. - Якщо ми хочемо реекспортувати як іменовані експорти, так і експорти за замовчуванням тоді нам потрібні дві інструкції: + Якщо ми хочемо реекспортувати як іменовані експорти, так і типові, тоді нам потрібні дві інструкції: ```js export * from './user.js'; // для реекспорту іменованих експортів - export {default} from './user.js'; // для реекспорту експортів за замовчуванням + export {default} from './user.js'; // для реекспорту типових експортів ``` -Такі дивацтва для реекспорту експортів за замовчуванням є однією з причин чому деякі розробники недолюблюють експорти за замовчуванням та надають перевагу іменованим. +Такі дивацтва для реекспорту типових експортів є однією з причин чому деякі розробники недолюблюють типові експорти та надають перевагу іменованим. ## Підсумки @@ -423,14 +423,14 @@ export default class User { - `export {x [as y], ...}`. - Реекспорт: - `export {x [as y], ...} from "module"` - - `export * from "module"` (не реекспортує за замовчуванням). - - `export {default [as y]} from "module"` (реекспорт за замовчуванням). + - `export * from "module"` (не реекспортує типові експорти). + - `export {default [as y]} from "module"` (типовий реекспорт). Імпорт: - Імпорт іменованих експортів: - `import {x [as y], ...} from "module"` -- Імпорт експортів за замовчуванням: +- Імпорт типових експортів: - `import x from "module"` - `import {default as x} from "module"` - Імпортування всього: