This commit is contained in:
Ilya Kantor 2019-05-21 18:05:46 +03:00
parent 3ce2d96948
commit 7d6d4366a3
5 changed files with 34 additions and 28 deletions

View file

@ -2,7 +2,7 @@
Promisification -- is a long word for a simple transform. It's conversion of a function that accepts a callback into a function returning a promise. Promisification -- is a long word for a simple transform. It's conversion of a function that accepts a callback into a function returning a promise.
In other words, we create a wrapper-function that does the same, internally calling the original one, but returns a promise. To be more precise, we create a wrapper-function that does the same, internally calling the original one, but returns a promise.
Such transforms are often needed in real-life, as many functions and libraries are callback-based. But promises are more convenient. So it makes sense to promisify those. Such transforms are often needed in real-life, as many functions and libraries are callback-based. But promises are more convenient. So it makes sense to promisify those.
@ -105,7 +105,7 @@ f = promisify(f, true);
f(...).then(arrayOfResults => ..., err => ...) f(...).then(arrayOfResults => ..., err => ...)
``` ```
In some cases, `err` may be absent at all: `callback(result)`, or there's something exotic in the callback format, then we can promisify such functions manually. In some cases, `err` may be absent at all: `callback(result)`, or there's something exotic in the callback format, then we can promisify such functions without using the helper, manually.
There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that. There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that.

View file

@ -6,7 +6,7 @@ A module usually contains a class or a library of useful functions.
For a long time, JavaScript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. For a long time, JavaScript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need.
But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules. But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules, special libraries to load modules on demand.
For instance: For instance:
@ -20,9 +20,9 @@ Now all these slowly become a part of history, but we still can find them in old
A module is just a file, a single script, as simple as that. A module is just a file, a single script, as simple as that.
Directives `export` and `import` allow to interchange functionality between modules: There are directives `export` and `import` to interchange functionality between modules, call functions of one module from another one:
- `export` keyword labels variables and functions that should be accessible from outside the file. - `export` keyword labels variables and functions that should be accessible from outside the current module.
- `import` allows to import functionality from other modules. - `import` allows to import functionality from other modules.
For instance, if we have a file `sayHi.js` exporting a function: For instance, if we have a file `sayHi.js` exporting a function:
@ -44,13 +44,15 @@ alert(sayHi); // function...
sayHi('John'); // Hello, John! sayHi('John'); // Hello, John!
``` ```
In this tutorial we concentrate on the language itself, but we use browser as the demo environment, so let's see how modules work in the browser. In this tutorial we concentrate on the language itself, but we use browser as the demo environment, so let's see how to use modules in the browser.
To use modules, we must set the attribute `<script type="module">`, like this: As modules support special keywords and features, we must tell the browser that a script should be treated as module, by using the attribute `<script type="module">`.
Like this:
[codetabs src="say" height="140" current="index.html"] [codetabs src="say" height="140" current="index.html"]
The browser automatically fetches and evaluates imports, then runs the script. The browser automatically fetches and evaluates imported modules, and then runs the script.
## Core module features ## Core module features
@ -60,7 +62,7 @@ There are core features, valid both for browser and server-side JavaScript.
### Always "use strict" ### Always "use strict"
Modules always `use strict`. E.g. assigning to an undeclared variable will give an error. Modules always `use strict`, by default. E.g. assigning to an undeclared variable will give an error.
```html run ```html run
<script type="module"> <script type="module">
@ -101,7 +103,7 @@ In the browser, independent top-level scope also exists for each `<script type="
</script> </script>
``` ```
If we really need to make a "global" in-browser variable, we can explicitly assign it to `window` and access as `window.user`. But that's an exception requiring a good reason. If we really need to make a window-level global variable, we can explicitly assign it to `window` and access as `window.user`. But that's an exception requiring a good reason.
### A module code is evaluated only the first time when imported ### A module code is evaluated only the first time when imported
@ -229,11 +231,11 @@ You may want skip those for now if you're reading for the first time, or if you
Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts. Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts.
In other words: In other words:
- external module scripts `<script type="module" src="...">` don't block HTML processing. - external module scripts `<script type="module" src="...">` don't block HTML processing, they load in parallel with other resources.
- module scripts wait until the HTML document is fully ready. - module scripts wait until the HTML document is fully ready (even if they are tiny and load faster than HTML), and then run.
- relative order is maintained: scripts that go first in the document, execute first. - relative order of scripts is maintained: scripts that go first in the document, execute first.
As a side-effect, module scripts always see HTML elements below them. As a side-effect, module scripts always "see" the fully loaded HTML-page, including HTML elements below them.
For instance: For instance:
@ -245,6 +247,8 @@ For instance:
// as modules are deferred, the script runs after the whole page is loaded // as modules are deferred, the script runs after the whole page is loaded
</script> </script>
Compare to regular script below:
<script> <script>
*!* *!*
alert(typeof button); // Error: button is undefined, the script can't see elements below alert(typeof button); // Error: button is undefined, the script can't see elements below
@ -259,7 +263,7 @@ Please note: the second script actually works before the first! So we'll see `un
That's because modules are deferred, so way wait for the document to be processed. The regular scripts runs immediately, so we saw its output first. That's because modules are deferred, so way wait for the document to be processed. The regular scripts runs immediately, so we saw its output first.
When using modules, we should be aware that HTML-document can show up before the JavaScript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused because of it. When using modules, we should be aware that HTML-page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused by that.
### Async works on inline scripts ### Async works on inline scripts
@ -303,7 +307,7 @@ There are two notable differences of external module scripts:
### No "bare" modules allowed ### No "bare" modules allowed
In the browser, in scripts (not in HTML), `import` must get either a relative or absolute URL. Modules without any path are called "bare" modules. Such modules are not allowed in `import`. In the browser, `import` must get either a relative or absolute URL. Modules without any path are called "bare" modules. Such modules are not allowed in `import`.
For instance, this `import` is invalid: For instance, this `import` is invalid:
```js ```js
@ -311,7 +315,7 @@ import {sayHi} from 'sayHi'; // Error, "bare" module
// the module must have a path, e.g. './sayHi.js' or wherever the module is // the module must have a path, e.g. './sayHi.js' or wherever the module is
``` ```
Certain environments, like Node.js or bundle tools allow bare modules, as they have own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet. Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet.
### Compatibility, "nomodule" ### Compatibility, "nomodule"
@ -362,7 +366,7 @@ To summarize, the core concepts are:
1. A module is a file. To make `import/export` work, browsers need `<script type="module">`, that implies several differences: 1. A module is a file. To make `import/export` work, browsers need `<script type="module">`, that implies several differences:
- Deferred by default. - Deferred by default.
- Async works on inline scripts. - Async works on inline scripts.
- External scripts need CORS headers. - To load external scripts from another origin (domain/protocol/port), CORS headers are needed.
- Duplicate external scripts are ignored. - Duplicate external scripts are ignored.
2. Modules have their own, local top-level scope and interchange functionality via `import/export`. 2. Modules have their own, local top-level scope and interchange functionality via `import/export`.
3. Modules always `use strict`. 3. Modules always `use strict`.

View file

@ -1,4 +1,6 @@
1. Yes, true. The element `elem.lastChild` is always the last one, it has no `nextSibling`, so if there are children, then yes. 1. Yes, true. The element `elem.lastChild` is always the last one, it has no `nextSibling`.
2. No, wrong, because `elem.children[0]` is the first child among elements. But there may be non-element nodes before it. So `previousSibling` may be a text node. 2. No, wrong, because `elem.children[0]` is the first child *among elements*. But there may exist non-element nodes before it. So `previousSibling` may be a text node. Also, if there are no children, then trying to access `elem.children[0]`
Please note that for both cases if there are no children, then there will be an error. For instance, if `elem.lastChild` is `null`, we can't access `elem.lastChild.nextSibling`. Please note: for both cases if there are no children, then there will be an error.
If there are no children, `elem.lastChild` is `null`, so we can't access `elem.lastChild.nextSibling`. And the collection `elem.children` is empty (like an empty array `[]`).

View file

@ -7,7 +7,7 @@ libs:
# Walking the DOM # Walking the DOM
The DOM allows us to do anything with elements and their contents, but first we need to reach the corresponding DOM object, get it into a variable, and then we are able to modify it. The DOM allows us to do anything with elements and their contents, but first we need to reach the corresponding DOM object.
All operations on the DOM start with the `document` object. From it we can access any node. All operations on the DOM start with the `document` object. From it we can access any node.
@ -86,7 +86,7 @@ For instance, here `<body>` has children `<div>` and `<ul>` (and few blank text
</html> </html>
``` ```
...And if we ask for all descendants of `<body>`, then we get direct children `<div>`, `<ul>` and also more nested elements like `<li>` (being a child of `<ul>`) and `<b>` (being a child of `<li>`) -- the entire subtree. ...And all descendants of `<body>` are not only direct children `<div>`, `<ul>` but also more deeply nested elements, such as `<li>` (a child of `<ul>`) and `<b>` (a child of `<li>`) -- the entire subtree.
**The `childNodes` collection provides access to all child nodes, including text nodes.** **The `childNodes` collection provides access to all child nodes, including text nodes.**

View file

@ -47,7 +47,7 @@ alert("color: #123ABC".match(reg)); // 123ABC
There are also properties with a value. For instance, Unicode "Script" (a writing system) can be Cyrillic, Greek, Arabic, Han (Chinese) etc, the [list is long]("https://en.wikipedia.org/wiki/Script_(Unicode)"). There are also properties with a value. For instance, Unicode "Script" (a writing system) can be Cyrillic, Greek, Arabic, Han (Chinese) etc, the [list is long]("https://en.wikipedia.org/wiki/Script_(Unicode)").
To search for certain scripts, we should supply `Script=<value>`, e.g. to search for cyrillic letters: `\p{sc=Cyrillic}`, for Chinese glyphs: `\p{sc=Han}`, etc: To search for characters in certain scripts ("alphabets"), we should supply `Script=<value>`, e.g. to search for cyrillic letters: `\p{sc=Cyrillic}`, for Chinese glyphs: `\p{sc=Han}`, etc:
```js run ```js run
let regexp = /\p{sc=Han}+/gu; // get chinese words let regexp = /\p{sc=Han}+/gu; // get chinese words
@ -59,15 +59,15 @@ alert( str.match(regexp) ); // 你好
## Building multi-language \w ## Building multi-language \w
Let's make a "universal" regexp for `pattern:\w`, for any language. That task has a standard solution in many programming languages with unicode-aware regexps, e.g. Perl. The pattern `pattern:\w` means "wordly characters", but doesn't work for languages that use non-Latin alphabets, such as Cyrillic and others. It's just a shorthand for `[a-zA-Z0-9_]`, so `pattern:\w+` won't find any Chinese words etc.
Let's make a "universal" regexp, that looks for wordly characters in any language. That's easy to do using Unicode properties:
```js ```js
/[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]/u /[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]/u
``` ```
Let's decipher. Remember, `pattern:\w` is actually the same as `pattern:[a-zA-Z0-9_]`. Let's decipher. Just as `pattern:\w` is the same as `pattern:[a-zA-Z0-9_]`, we're making a set of our own, that includes:
So the character set includes:
- `Alphabetic` for letters, - `Alphabetic` for letters,
- `Mark` for accents, as in Unicode accents may be represented by separate code points, - `Mark` for accents, as in Unicode accents may be represented by separate code points,