This commit is contained in:
Ilya Kantor 2019-05-29 21:38:58 +03:00
parent 16e7d07dc0
commit 0873473402
7 changed files with 27 additions and 24 deletions

View file

@ -8,7 +8,7 @@ Everyone is happy, because the people don't crowd you any more, and fans, becaus
This is a real-life analogy for things we often have in programming: This is a real-life analogy for things we often have in programming:
1. A "producing code" that does something and takes time. For instance, the code loads a remote script. That's a "singer". 1. A "producing code" that does something and takes time. For instance, the code loads data over a network. That's a "singer".
2. A "consuming code" that wants the result of the "producing code" once it's ready. Many functions may need that result. These are the "fans". 2. A "consuming code" that wants the result of the "producing code" once it's ready. Many functions may need that result. These are the "fans".
3. A *promise* is a special JavaScript object that links the "producing code" and the "consuming code" together. In terms of our analogy: this is the "subscription list". The "producing code" takes whatever time it needs to produce the promised result, and the "promise" makes that result available to all of the subscribed code when it's ready. 3. A *promise* is a special JavaScript object that links the "producing code" and the "consuming code" together. In terms of our analogy: this is the "subscription list". The "producing code" takes whatever time it needs to produce the promised result, and the "promise" makes that result available to all of the subscribed code when it's ready.
@ -27,7 +27,7 @@ The function passed to `new Promise` is called the *executor*. When the promise
The resulting `promise` object has internal properties: The resulting `promise` object has internal properties:
- `state` — initially "pending", then changes to either "fulfilled" or "rejected", - `state` — initially "pending", then changes to either "fulfilled" or "rejected",
- `result` — an arbitrary value of your choosing, initially `undefined`. - `result` — an arbitrary value, initially `undefined`.
When the executor finishes the job, it should call one of the functions that it gets as arguments: When the executor finishes the job, it should call one of the functions that it gets as arguments:
@ -56,7 +56,7 @@ let promise = new Promise(function(resolve, reject) {
We can see two things by running the code above: We can see two things by running the code above:
1. The executor is called automatically and immediately (by the `new Promise`). 1. The executor is called automatically and immediately (by the `new Promise`).
2. The executor receives two arguments: `resolve` and `reject` — these functions are pre-defined by the JavaScript engine. So we don't need to create them. Instead, we should write the executor to call them when ready. 2. The executor receives two arguments: `resolve` and `reject` — these functions are pre-defined by the JavaScript engine. So we don't need to create them. We only should call one of them when ready.
After one second of "processing" the executor calls `resolve("done")` to produce the result: After one second of "processing" the executor calls `resolve("done")` to produce the result:
@ -77,7 +77,7 @@ let promise = new Promise(function(resolve, reject) {
To summarize, the executor should do a job (something that takes time usually) and then call `resolve` or `reject` to change the state of the corresponding Promise object. To summarize, the executor should do a job (something that takes time usually) and then call `resolve` or `reject` to change the state of the corresponding Promise object.
The Promise that is either resolved or rejected is called "settled", as opposed to a "pending" Promise. The Promise that is either resolved or rejected is called "settled", as opposed to a initially "pending" Promise.
````smart header="There can be only a single result or an error" ````smart header="There can be only a single result or an error"
The executor should call only one `resolve` or one `reject`. The promise's state change is final. The executor should call only one `resolve` or one `reject`. The promise's state change is final.
@ -112,9 +112,9 @@ let promise = new Promise(function(resolve, reject) {
}); });
``` ```
For instance, this might happen when we start to do a job but then see that everything has already been completed. For instance, this might happen when we start to do a job but then see that everything has already been completed and cached.
That's fine. We immediately have a resolved Promise, nothing wrong with that. That's fine. We immediately have a resolved promise.
```` ````
```smart header="The `state` and `result` are internal" ```smart header="The `state` and `result` are internal"
@ -140,12 +140,12 @@ promise.then(
The first argument of `.then` is a function that: The first argument of `.then` is a function that:
1. runs when the Promise is resolved, and 1. runs when the promise is resolved, and
2. receives the result. 2. receives the result.
The second argument of `.then` is a function that: The second argument of `.then` is a function that:
1. runs when the Promise is rejected, and 1. runs when the promise is rejected, and
2. receives the error. 2. receives the error.
For instance, here's a reaction to a successfully resolved promise: For instance, here's a reaction to a successfully resolved promise:
@ -233,10 +233,10 @@ new Promise((resolve, reject) => {
.then(result => show result, err => show error) .then(result => show result, err => show error)
``` ```
It's not exactly an alias though. There are several important differences: It's not exactly an alias of `then(f,f)` though. There are several important differences:
1. A `finally` handler has no arguments. In `finally` we don't know whether the promise is successful or not. That's all right, as our task is usually to perform "general" finalizing procedures. 1. A `finally` handler has no arguments. In `finally` we don't know whether the promise is successful or not. That's all right, as our task is usually to perform "general" finalizing procedures.
2. Finally passes through results and errors to the next handler. 2. A `finally` handler passes through results and errors to the next handler.
For instance, here the result is passed through `finally` to `then`: For instance, here the result is passed through `finally` to `then`:
```js run ```js run
@ -257,11 +257,11 @@ It's not exactly an alias though. There are several important differences:
.catch(err => alert(err)); // <-- .catch handles the error object .catch(err => alert(err)); // <-- .catch handles the error object
``` ```
That's very convenient, because finally is not meant to process promise results. So it passes them through. That's very convenient, because `finally` is not meant to process a promise result. So it passes it through.
We'll talk more about promise chaining and result-passing between handlers in the next chapter. We'll talk more about promise chaining and result-passing between handlers in the next chapter.
3. Last, but not least, `.finally(f)` is a more convenient syntax than `.then(f, f)`: no need to duplicate the function. 3. Last, but not least, `.finally(f)` is a more convenient syntax than `.then(f, f)`: no need to duplicate the function `f`.
````smart header="On settled promises handlers runs immediately" ````smart header="On settled promises handlers runs immediately"
If a promise is pending, `.then/catch/finally` handlers wait for the result. Otherwise, if a promise has already settled, they execute immediately: If a promise is pending, `.then/catch/finally` handlers wait for the result. Otherwise, if a promise has already settled, they execute immediately:

View file

@ -78,12 +78,13 @@
} }
document.onmouseout = function() { document.onmouseout = function() {
// it is possible that mouseout triggered, but we're still inside the element (cause of bubbling) // it is possible that mouseout triggered, but we're still inside the element
// (its target was inside, and it bubbled)
// but in this case we'll have an immediate mouseover, // but in this case we'll have an immediate mouseover,
// so the tooltip will be destroyed and shown again // so the tooltip will be destroyed and shown again
// //
// that's an overhead, but here it's not visible // luckily, the "blinking" won't be visible,
// can be fixed with additional checks // as both events happen almost at the same time
if (tooltip) { if (tooltip) {
tooltip.remove(); tooltip.remove();
tooltip = false; tooltip = false;

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en"> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">

View file

@ -13,7 +13,7 @@ Technically, we can measure the mouse speed over the element, and if it's slow t
Make a universal object `new HoverIntent(options)` for it. With `options`: Make a universal object `new HoverIntent(options)` for it. With `options`:
- `elem` -- element to track. - `elem` -- element to track.
- `over` -- a function to call if the mouse is slowly moving the element. - `over` -- a function to call if the mouse is slowly moving over the element.
- `out` -- a function to call when the mouse leaves the element (if `over` was called). - `out` -- a function to call when the mouse leaves the element (if `over` was called).
An example of using such object for the tooltip: An example of using such object for the tooltip:

View file

@ -10,15 +10,17 @@ The `mouseover` event occurs when a mouse pointer comes over an element, and `mo
These events are special, because they have a `relatedTarget`. These events are special, because they have a `relatedTarget`.
This property complements `target`. When a mouse leaves one element for another, one of them becomes `target`, and the other one `relatedTarget`.
For `mouseover`: For `mouseover`:
- `event.target` -- is the element where the mouse came over. - `event.target` -- is the element where the mouse came over.
- `event.relatedTarget` -- is the element from which the mouse came. - `event.relatedTarget` -- is the element from which the mouse came (`relatedTarget` -> `target`).
For `mouseout` the reverse: For `mouseout` the reverse:
- `event.target` -- is the element that mouse left. - `event.target` -- is the element that mouse left.
- `event.relatedTarget` -- is the new under-the-pointer element (that mouse left for). - `event.relatedTarget` -- is the new under-the-pointer element, that mouse left for (`target` -> `relatedTarget`).
```online ```online
In the example below each face feature is an element. When you move the mouse, you can see mouse events in the text area. In the example below each face feature is an element. When you move the mouse, you can see mouse events in the text area.

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en"> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">

View file

@ -1,6 +1,6 @@
# File and FileReader # File and FileReader
A [File](https://www.w3.org/TR/FileAPI/#dfn-file) object inherits from `Blob`, but is extended with filesystem-related capabilities. A [File](https://www.w3.org/TR/FileAPI/#dfn-file) object inherits from `Blob` and is extended with filesystem-related capabilities.
There are two ways to obtain it. There are two ways to obtain it.
@ -38,9 +38,9 @@ The input may select multiple files, so `input.files` is an array-like object wi
## FileReader ## FileReader
[FileReader](https://www.w3.org/TR/FileAPI/#dfn-filereader) is an object with the sole purpose of reading from `Blob` (and hence `File` too) objects. [FileReader](https://www.w3.org/TR/FileAPI/#dfn-filereader) is an object with the sole purpose of reading data from `Blob` (and hence `File` too) objects.
It's event based, as reading from disk may take time. It delivers the data using events, as reading from disk may take time.
The constructor: The constructor:
@ -109,7 +109,7 @@ For Web Workers, there also exists a synchronous variant of `FileReader`, called
Its reading methods `read*` do not generate events, but rather return a result, as regular functions do. Its reading methods `read*` do not generate events, but rather return a result, as regular functions do.
That's only inside a Web Worker though, because delays and hang-ups in Web Workers are less important, they do not affect the page. That's only inside a Web Worker though, because delays in synchronous calls, that are possible while reading from files, in Web Workers are less important. They do not affect the page.
``` ```
## Summary ## Summary