Merge branch 'master' into patch-52
This commit is contained in:
commit
32c2432f95
4 changed files with 15 additions and 15 deletions
|
@ -109,13 +109,13 @@ As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that mean
|
|||
|
||||
Now let's make a mixin for real life.
|
||||
|
||||
An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows to easily add event-related functions to any class/object.
|
||||
An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object.
|
||||
|
||||
- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data.
|
||||
- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from `.trigger` call.
|
||||
- ...And the method `.off(name, handler)` that removes `handler` listener.
|
||||
- ...And the method `.off(name, handler)` that removes the `handler` listener.
|
||||
|
||||
After adding the mixin, an object `user` will become able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen to such events to load the calendar for the logged-in person.
|
||||
After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person.
|
||||
|
||||
Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may assign handlers to react on that event. And so on.
|
||||
|
||||
|
@ -165,7 +165,7 @@ let eventMixin = {
|
|||
```
|
||||
|
||||
|
||||
- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name happens. Technically, there's `_eventHandlers` property, that stores an array of handlers for each event name. So it just adds it to the list.
|
||||
- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list.
|
||||
- `.off(eventName, handler)` -- removes the function from the handlers list.
|
||||
- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.
|
||||
|
||||
|
@ -193,7 +193,7 @@ menu.on("select", value => alert(`Value selected: ${value}`));
|
|||
menu.choose("123");
|
||||
```
|
||||
|
||||
Now if we'd like any code to react on menu selection, we can listen to it with `menu.on(...)`.
|
||||
Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`.
|
||||
|
||||
And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
|
||||
|
||||
|
@ -203,6 +203,6 @@ And `eventMixin` mixin makes it easy to add such behavior to as many classes as
|
|||
|
||||
Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
|
||||
|
||||
We can use mixins as a way to augment a class by multiple behaviors, like event-handling as we have seen above.
|
||||
We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
|
||||
|
||||
Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that.
|
||||
Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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.
|
||||
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.
|
||||
|
||||
|
@ -25,8 +25,8 @@ try {
|
|||
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 `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.
|
||||
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 `try` execution is stopped, and the control flows to the beginning of `catch(err)`. The `err` variable (can use any name for it) will contain an error object with details about what happened.
|
||||
|
||||

|
||||
|
||||
|
@ -668,4 +668,4 @@ We can also generate our own errors using the `throw` operator. Technically, the
|
|||
|
||||
*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 to setup a "global" error handler to catch errors that "fall out". In-browser that's `window.onerror`.
|
||||
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`.
|
||||
|
|
|
@ -23,7 +23,7 @@ Our function `readUser(json)` will not only read JSON, but check ("validate") th
|
|||
|
||||
Our `ValidationError` class should inherit from the built-in `Error` class.
|
||||
|
||||
That class is built-in, here's it approximate code, for us to understand what we're extending:
|
||||
That class is built-in, but here's its approximate code so we can understand what we're extending:
|
||||
|
||||
```js
|
||||
// The "pseudocode" for the built-in Error class defined by JavaScript itself
|
||||
|
@ -215,9 +215,9 @@ Now custom errors are much shorter, especially `ValidationError`, as we got rid
|
|||
|
||||
The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors.
|
||||
|
||||
The code which calls `readUser` should handle these errors. Right now it uses multiple `if` in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. But if `readUser` function generates several kinds of errors -- then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
|
||||
The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. But if the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
|
||||
|
||||
Often the answer is "No": the outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is often irrelevant (the error message describes it). Or, even better if there is a way to get error details, but only if we need to.
|
||||
Often the answer is "No": the outer code wants to be "one level above all that", it just wants to have some kind of "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, it could have a way to get the error details, but only if we need to.
|
||||
|
||||
So let's make a new class `ReadError` to represent such errors. If an error occurs inside `readUser`, we'll catch it there and generate `ReadError`. We'll also keep the reference to the original error in its `cause` property. Then the outer code will only have to check for `ReadError`.
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ new Promise(resolve => resolve(1))
|
|||
|
||||
JavaScript checks the object returned by `.then` handler in the line `(*)`: if it has a callable method named `then`, then it calls that method providing native functions `resolve`, `reject` as arguments (similar to executor) and waits until one of them is called. In the example above `resolve(2)` is called after 1 second `(**)`. Then the result is passed further down the chain.
|
||||
|
||||
This feature allows to integrate custom objects with promise chains without having to inherit from `Promise`.
|
||||
This feature allows us to integrate custom objects with promise chains without having to inherit from `Promise`.
|
||||
````
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue