Skip to content

Commit d04c798

Browse files
authored
Merge pull request #219 from vplentinax/sync-errorHand
Sincronización 10-error-handling
2 parents 5dd1979 + 9bdfd11 commit d04c798

File tree

6 files changed

+109
-143
lines changed

6 files changed

+109
-143
lines changed

‎1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ function f(){
4444
f(); // cleanup!
4545
```
4646

47-
It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run.
47+
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.

‎1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ Compare the two code fragments.
3333
*/!*
3434
```
3535

36-
We definitely need the cleanup after the work has started, doesn't matter if there was an error or not.
36+
We definitely need the cleanup after the work, doesn't matter if there was an error or not.
3737
3838
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.

‎1-js/10-error-handling/1-try-catch/article.md‎

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Error handling, "try..catch"
22

3-
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 of other reasons.
3+
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.
44

55
Usually, a script "dies" (immediately stops) in case of an error, printing it to console.
66

7-
But there's a syntax construct `try..catch` that allows to "catch" errors and, instead of dying, do something more reasonable.
7+
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.
88

99
## The "try..catch" syntax
1010

@@ -25,14 +25,14 @@ try{
2525
It works like this:
2626

2727
1. First, the code in `try{...}` is executed.
28-
2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and then jumps over`catch`.
29-
3. If an error occurs, then `try` execution is stopped, and the control flows to the beginning of `catch(err)`. The `err` variable (can use any name for it) contains an error object with details about what's happened.
28+
2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and goes on, skipping`catch`.
29+
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.
3030

3131
![](try-catch-flow.svg)
3232

33-
So, an error inside the `try{…}` block does not kill the script: we have a chance to handle it in `catch`.
33+
So, an error inside the `try{…}` block does not kill the script -- we have a chance to handle it in `catch`.
3434

35-
Let's see more examples.
35+
Let's look at some examples.
3636

3737
- An errorless example: shows `alert``(1)` and `(2)`:
3838

@@ -50,8 +50,6 @@ Let's see more examples.
5050
alert('Catch is ignored, because there are no errors'); // (3)
5151

5252
}
53-
54-
alert("...Then the execution continues");
5553
```
5654
- An example with an error: shows `(1)` and `(3)`:
5755

@@ -68,11 +66,9 @@ Let's see more examples.
6866
6967
} catch(err){
7068
71-
alert(`Error has occured!`); // *!*(3) <--*/!*
69+
alert(`Error has occurred!`); // *!*(3) <--*/!*
7270
7371
}
74-
75-
alert("...Then the execution continues");
7672
```
7773

7874

@@ -89,9 +85,9 @@ try{
8985
}
9086
```
9187
92-
The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phrase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code.
88+
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.
9389
94-
So, `try..catch` can only handle errors that occur in the valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
90+
So, `try..catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
9591
````
9692
9793
@@ -108,7 +104,7 @@ try{
108104
}
109105
```
110106

111-
That's because `try..catch` actually wraps the `setTimeout` call that schedules the function. But the function itself is executed later, when the engine has already left the `try..catch` construct.
107+
That's because the function itself is executed later, when the engine has already left the `try..catch` construct.
112108
113109
To catch an exception inside a scheduled function, `try..catch` must be inside that function:
114110
```js run
@@ -134,10 +130,10 @@ try{
134130
}
135131
```
136132
137-
For all built-in errors, the error object inside `catch` block has two main properties:
133+
For all built-in errors, the error object has two main properties:
138134
139135
`name`
140-
: Error name. For an undefined variable that's `"ReferenceError"`.
136+
: Error name. For instance, for an undefined variable that's `"ReferenceError"`.
141137

142138
`message`
143139
: Textual message about error details.
@@ -157,7 +153,7 @@ try{
157153
} catch(err){
158154
alert(err.name); // ReferenceError
159155
alert(err.message); // lalala is not defined
160-
alert(err.stack); // ReferenceError: lalala is not defined at ...
156+
alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)
161157
162158
// Can also show an error as a whole
163159
// The error is converted to string as "name: message"
@@ -174,8 +170,8 @@ If we don't need error details, `catch` may omit it:
174170
```js
175171
try{
176172
// ...
177-
} catch{
178-
// error object omitted
173+
} catch{ // <-- without (err)
174+
// ...
179175
}
180176
```
181177
@@ -187,7 +183,7 @@ As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse)
187183

188184
Usually it's used to decode data received over the network, from the server or another source.
189185
190-
We receive it and call `JSON.parse`, like this:
186+
We receive it and call `JSON.parse` like this:
191187
192188
```js run
193189
let json = '{"name":"John", "age":30}'; // data from the server
@@ -205,7 +201,7 @@ You can find more detailed information about JSON in the <info:json> chapter.
205201
206202
**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".**
207203
208-
Should we be satisfied with that? Of course, not!
204+
Should we be satisfied with that? Of course not!
209205
210206
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.
211207
@@ -302,13 +298,13 @@ try{
302298
*!*
303299
alert(e.name); // SyntaxError
304300
*/!*
305-
alert(e.message); // Unexpected token o in JSON at position 0
301+
alert(e.message); // Unexpected token b in JSON at position 2
306302
}
307303
```
308304
309305
As we can see, that's a `SyntaxError`.
310306
311-
And in our case, the absence of `name` could be treated as a syntax error also, assuming that users must have a `name`.
307+
And in our case, the absence of `name` is an error, as users must have a `name`.
312308
313309
So let's throw it:
314310
@@ -338,9 +334,9 @@ Now `catch` became a single place for all error handling: both for `JSON.parse`
338334
339335
## Rethrowing
340336
341-
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 variable is undefined or something else, not just that"incorrect data" thing.
337+
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.
342338
343-
Like this:
339+
For example:
344340
345341
```js run
346342
let json = '{"age": 30 }' // incomplete data
@@ -355,31 +351,35 @@ try{
355351
}
356352
```
357353
358-
Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a crazy bug may be discovered that leads to terrible hacks (like it happened with the `ssh` tool).
354+
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.
355+
356+
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 `"JSONError"` message. That's wrong and also makes the code more difficult to debug.
357+
358+
To avoid such problems, we can employ the "rethrowing" technique. The rule is simple:
359+
360+
**Catch should only process errors that it knows and "rethrow" all others.**
361+
362+
The "rethrowing" technique can be explained in more detail as:
359363
360-
In our case, `try..catch` is meant 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 `"JSONError"` message. That's wrong and also makes the code more difficult to debug.
364+
1. Catch gets all errors.
365+
2. In the `catch(err){...}` block we analyze the error object `err`.
366+
2. If we don't know how to handle it, we do `throw err`.
361367
362-
Fortunately, we can find out which error we get, for instance from its `name`:
368+
Usually, we can check the error type using the `instanceof` operator:
363369
364370
```js run
365371
try{
366372
user ={/*...*/ };
367-
} catch(e){
373+
} catch(err){
368374
*!*
369-
alert(e.name); // "ReferenceError" for accessing an undefined variable
375+
if (err instanceof ReferenceError){
370376
*/!*
377+
alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable
378+
}
371379
}
372380
```
373381
374-
The rule is simple:
375-
376-
**Catch should only process errors that it knows and "rethrow" all others.**
377-
378-
The "rethrowing" technique can be explained in more detail as:
379-
380-
1. Catch gets all errors.
381-
2. In `catch(err){...}` block we analyze the error object `err`.
382-
2. If we don't know how to handle it, then we do `throw err`.
382+
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`.
383383
384384
In the code below, we use rethrowing so that `catch` only handles `SyntaxError`:
385385
@@ -402,7 +402,7 @@ try{
402402
} catch(e){
403403
404404
*!*
405-
if (e.name == "SyntaxError"){
405+
if (e instanceof SyntaxError){
406406
alert( "JSONError:" + e.message );
407407
} else{
408408
throw e; // rethrow (*)
@@ -429,7 +429,7 @@ function readData(){
429429
*/!*
430430
} catch (e){
431431
// ...
432-
if (e.name != 'SyntaxError'){
432+
if (!(e instanceof SyntaxError)){
433433
*!*
434434
throw e; // rethrow (don't know how to deal with it)
435435
*/!*
@@ -489,7 +489,7 @@ The code has two ways of execution:
489489
1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`.
490490
2. If you say "No", then `try -> finally`.
491491
492-
The `finally` clause is often used when we start doing something before `try..catch` and want to finalize it in any case of outcome.
492+
The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome.
493493
494494
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.
495495
@@ -521,20 +521,20 @@ try{
521521
}
522522
*/!*
523523
524-
alert(result || "error occured");
524+
alert(result || "error occurred");
525525
526526
alert( `execution took ${diff}ms` );
527527
```
528528
529-
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, an the execution will take `0ms`. Both measurements are done correctly.
529+
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.
530530
531-
In other words, there may be two ways to exit a function: either a `return` or `throw`. The `finally` clause handles them both.
531+
In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases.
532532
533533
534534
```smart header="Variables are local inside `try..catch..finally`"
535535
Please note that `result` and `diff` variables in the code above are declared *before* `try..catch`.
536536
537-
Otherwise, if `let` were made inside the `{...}` block, it would only be visible inside of it.
537+
Otherwise, if we declared `let` in `try` block, it would only be visible inside of it.
538538
```
539539
540540
````smart header="`finally` and `return`"
@@ -565,7 +565,7 @@ alert( func() ); // first works alert from finally, and then this one
565565
566566
````smart header="`try..finally`"
567567
568-
The `try..finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors right here, but want to be sure that processes that we started are finalized.
568+
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.
569569
570570
```js
571571
function func(){
@@ -577,7 +577,7 @@ function func(){
577577
}
578578
}
579579
```
580-
In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow jumps outside.
580+
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.
581581
````
582582
583583
## Global catch
@@ -586,11 +586,11 @@ In the code above, an error inside `try` always falls out, because there's no `c
586586
The information from this section is not a part of the core JavaScript.
587587
```
588588
589-
Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible.
589+
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.
590590
591-
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.
591+
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.
592592
593-
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 special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error.
593+
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.
594594
595595
The syntax:
596596
@@ -637,13 +637,13 @@ There are also web-services that provide error-logging for such cases, like <htt
637637
They work like this:
638638
639639
1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages.
640-
2. That JS script has a custom `window.onerror` function.
640+
2. That JS script sets a custom `window.onerror` function.
641641
3. When an error occurs, it sends a network request about it to the service.
642642
4. We can log in to the service web interface and see errors.
643643
644644
## Summary
645645
646-
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.
646+
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.
647647
648648
The syntax is:
649649
@@ -658,18 +658,18 @@ try{
658658
}
659659
```
660660
661-
There may be no `catch` section or no `finally`, so `try..catch` and `try..finally` are also valid.
661+
There may be no `catch` section or no `finally`, so shorter constructs `try..catch` and `try..finally` are also valid.
662662
663663
Error objects have following properties:
664664
665665
- `message` -- the human-readable error message.
666666
- `name` -- the string with error name (error constructor name).
667-
- `stack` (non-standard) -- the stack at the moment of error creation.
667+
- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation.
668668
669-
If error is not needed, we can omit it by using `catch{` instead of `catch(err){`.
669+
If an error object is not needed, we can omit it by using `catch{` instead of `catch(err){`.
670670
671671
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.
672672
673-
Rethrowing is a basic 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.
673+
*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.
674674
675-
Even if we don't have `try..catch`, most environments allow to setup a "global" error handler to catch errors that "fall out". In-browser that's `window.onerror`.
675+
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`.

0 commit comments

Comments
(0)