-
Notifications
You must be signed in to change notification settings - Fork 0
/
javascript-advanced-features.html
201 lines (177 loc) · 42.6 KB
/
javascript-advanced-features.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<!DOCTYPE html><html lang="de-ch"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>JavaScript advanced features - Finecloud</title><meta name="description" content="New Features New versions of JavaScript, such as ES6, ES2016, 2017, etc., come with many new features, however it is still ECMAScript Many of the new features are syntactic sugar or extend the functionality only marginal Template Literals Template literals are string literals with support…"><meta name="generator" content="Publii Open-Source CMS for Static Site"><link rel="stylesheet" href="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism-black.css"><link rel="canonical" href="https://www.finecloud.ch/javascript-advanced-features.html"><link rel="alternate" type="application/atom+xml" href="https://www.finecloud.ch/feed.xml"><link rel="alternate" type="application/json" href="https://www.finecloud.ch/feed.json"><meta property="og:title" content="JavaScript advanced features"><meta property="og:site_name" content="Finecloud"><meta property="og:description" content="New Features New versions of JavaScript, such as ES6, ES2016, 2017, etc., come with many new features, however it is still ECMAScript Many of the new features are syntactic sugar or extend the functionality only marginal Template Literals Template literals are string literals with support…"><meta property="og:url" content="https://www.finecloud.ch/javascript-advanced-features.html"><meta property="og:type" content="article"><link rel="shortcut icon" href="https://www.finecloud.ch/media/website/finecloud.png" type="image/png"><link rel="stylesheet" href="https://www.finecloud.ch/assets/css/style.css?v=39da73365516a098a9b73b721fc970e2"><script type="application/ld+json">{"@context":"http://schema.org","@type":"Article","mainEntityOfPage":{"@type":"WebPage","@id":"https://www.finecloud.ch/javascript-advanced-features.html"},"headline":"JavaScript advanced features","datePublished":"2023-01-31T07:15","dateModified":"2023-03-29T20:14","description":"New Features New versions of JavaScript, such as ES6, ES2016, 2017, etc., come with many new features, however it is still ECMAScript Many of the new features are syntactic sugar or extend the functionality only marginal Template Literals Template literals are string literals with support…","author":{"@type":"Person","name":"Finecloud","url":"https://www.finecloud.ch/authors/finecloud/"},"publisher":{"@type":"Organization","name":"Finecloud"}}</script><meta name="google-site-verification" content="seFY9U12uiEq5U3_MyZiX6XWzk0AVFl9zITr2ZKsytY"></head><body><div class="site-container"><header class="top" id="js-header"><a class="logo" href="https://www.finecloud.ch/">Finecloud</a><nav class="navbar js-navbar"><button class="navbar__toggle js-toggle" aria-label="Menu" aria-haspopup="true" aria-expanded="false"><span class="navbar__toggle-box"><span class="navbar__toggle-inner">Menu</span></span></button><ul class="navbar__menu"><li><a href="https://www.finecloud.ch/" target="_self">Blog</a></li><li><a href="https://www.finecloud.ch/tags/" target="_self">Tags</a></li></ul></nav><div class="search"><div class="search__overlay js-search-overlay"><div class="search__overlay-inner"><form action="https://www.finecloud.ch/search.html" class="search__form"><input class="search__input js-search-input" type="search" name="q" placeholder="search..." aria-label="search..." autofocus="autofocus"></form><button class="search__close js-search-close" aria-label="Close">Close</button></div></div><button class="search__btn js-search-btn" aria-label="Search"><svg role="presentation" focusable="false"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#search"/></svg></button></div></header><main><article class="post"><div class="hero"><figure class="hero__image hero__image--overlay"><img src="https://www.finecloud.ch/media/website/download.jpg" srcset="https://www.finecloud.ch/media/website/responsive/download-xs.jpg 300w, https://www.finecloud.ch/media/website/responsive/download-sm.jpg 480w, https://www.finecloud.ch/media/website/responsive/download-md.jpg 768w, https://www.finecloud.ch/media/website/responsive/download-lg.jpg 1024w, https://www.finecloud.ch/media/website/responsive/download-xl.jpg 1360w, https://www.finecloud.ch/media/website/responsive/download-2xl.jpg 1600w" sizes="100vw" loading="eager" alt=""></figure><header class="hero__content"><div class="wrapper"><div class="post__meta"><time datetime="2023-01-31T07:15">Januar 31, 2023</time></div><h1>JavaScript advanced features</h1></div></header></div><div class="wrapper post__entry"><div class="post__toc"><h3>Table of Contents</h3><ul><li><a href="#mcetoc_1go3akel62sa">New Features</a><ul><li><a href="#mcetoc_1go3akel62sb">Template Literals</a></li><li><a href="#mcetoc_1go3akel62sc">Spread Operator</a></li><li><a href="#mcetoc_1go3akel62sd">Array and Object Destructuring</a></li><li><a href="#mcetoc_1go3akel62se">Arraw functions</a></li><li><a href="#mcetoc_1go3akel62sf">Classes</a></li><li><a href="#mcetoc_1go3akel62sg">Class Inheritance</a></li></ul></li><li><a href="#mcetoc_1go3akel62sh">Modules</a><ul><li><a href="#mcetoc_1go3akel62si">Global Scope</a></li><li><a href="#mcetoc_1go3akel62sj">IIFE</a></li><li><a href="#mcetoc_1go3akel62sk">Example jQuery Plugin</a></li><li><a href="#mcetoc_1go3r9h51351">Module Systems</a></li><li><a href="#mcetoc_1go3r9h51352">ES Modules</a></li><li><a href="#mcetoc_1go3r9h51353">Export Examples</a></li><li><a href="#mcetoc_1go3r9h51354">Import Examples</a></li><li><a href="#mcetoc_1go3r9h51355">Default Export</a></li><li><a href="#mcetoc_1go3r9h51356">Usage in the Browser</a></li></ul></li><li><a href="#mcetoc_1go3akel62sl">Promises</a><ul><li><a href="#mcetoc_1go41qk9o3km">Asynchronous Programming</a></li><li><a href="#mcetoc_1go41qk9o3kn">Promises Are State Machines</a></li></ul></li><li><a href="#mcetoc_1go41qk9o3ko">Creating Promises</a><ul><li><a href="#mcetoc_1go41qk9o3kp">Promise Example</a></li><li><a href="#mcetoc_1go41qk9o3kq">Chaining</a></li><li><a href="#mcetoc_1go41qk9o3kr">Chaining and Combining Examples</a></li><li><a href="#mcetoc_1go41qk9o3ks">async and await</a></li></ul></li><li><a href="#mcetoc_1go3akel62sm">Fetch API</a></li></ul></div><h2 id="mcetoc_1go3akel62sa">New Features</h2><ul><li>New versions of JavaScript, such as ES6, ES2016, 2017, etc., come with many new features, however it is still ECMAScript</li><li>Many of the new features are syntactic sugar or extend the functionality only marginal</li></ul><h3 id="mcetoc_1go3akel62sb">Template Literals</h3><ul><li>Template literals are string literals with support for text interpolation and multiple lines</li><li>Template literals are enclosed by backticks</li><li>Expressions in placeholders (marked by the dollar sign and curly braces) are evaluated and replaced by their value at runtime</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">getYear</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">return</span> (<span class="hljs-keyword" style="color: #cc7832;">new</span> <span class="hljs-built_in">Date</span>()).getFullYear();
}
<span class="hljs-keyword" style="color: #cc7832;">const</span> student = {
name: <span class="hljs-string" style="color: #6a8759;">"Bob"</span>,
age: <span class="hljs-number" style="color: #6897bb;">25</span>,
university: <span class="hljs-string" style="color: #6a8759;">"BFH"</span>
};
<span class="hljs-keyword" style="color: #cc7832;">const</span> message = <span class="hljs-string" style="color: #6a8759;">`<span class="hljs-subst">${student.name}</span> is a student at <span class="hljs-subst">${student.university}</span>.
<span class="hljs-subst">${student.name}</span> was born in <span class="hljs-subst">${getYear() - student.age}</span>.`</span>;
<span class="hljs-built_in">console</span>.log(message); <span class="hljs-comment" style="color: grey;">// >> Bob is a student at BFH.</span>
<span class="hljs-comment" style="color: grey;">// Bob was born in 1996.</span>
</pre><h3 id="mcetoc_1go3akel62sc">Spread Operator</h3><ul><li>Using the spread operator new arrays and objects can be created based on the values of other arrays or objects</li><li>The spread operator is especially useful to shallow-clone and merge or extend objects</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">const</span> a = [<span class="hljs-number" style="color: #6897bb;">1</span>, <span class="hljs-number" style="color: #6897bb;">2</span>];
<span class="hljs-keyword" style="color: #cc7832;">const</span> b = [<span class="hljs-number" style="color: #6897bb;">3</span>, <span class="hljs-number" style="color: #6897bb;">4</span>, <span class="hljs-number" style="color: #6897bb;">5</span>];
<span class="hljs-keyword" style="color: #cc7832;">const</span> clonedA = [...a];
clonedA[<span class="hljs-number" style="color: #6897bb;">1</span>] = <span class="hljs-number" style="color: #6897bb;">3</span>; <span class="hljs-comment" style="color: grey;">// a remains unaffected</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> mergedArr = [<span class="hljs-number" style="color: #6897bb;">0</span>, ...a, ...b, <span class="hljs-number" style="color: #6897bb;">6</span>]; <span class="hljs-comment" style="color: grey;">// [0, 1, 2, 3, 4, 5, 6]</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> x = {a: <span class="hljs-string" style="color: #6a8759;">"foo"</span>, b: <span class="hljs-number" style="color: #6897bb;">7</span>};
<span class="hljs-keyword" style="color: #cc7832;">const</span> y = {a: <span class="hljs-string" style="color: #6a8759;">"bar"</span>, c: <span class="hljs-number" style="color: #6897bb;">8</span>};
<span class="hljs-keyword" style="color: #cc7832;">const</span> clonedX = {...x};
clonedX.a = <span class="hljs-string" style="color: #6a8759;">"bar"</span>; <span class="hljs-comment" style="color: grey;">// x remains unaffected</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> mergedObj = {...x, ...y, c: <span class="hljs-number" style="color: #6897bb;">9</span>}; <span class="hljs-comment" style="color: grey;">// \{a: "bar", b: 7, c: 9\}</span>
</pre><h3 id="mcetoc_1go3akel62sd">Array and Object Destructuring</h3><ul><li>The destructuring assignment unpacks values from arrays and objects into distinct variables</li><li>Destructuring can also be used in function parameter definitions to unpack fields from objects passed as argument</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">const</span> a = [<span class="hljs-number" style="color: #6897bb;">1</span>, <span class="hljs-number" style="color: #6897bb;">2</span>, <span class="hljs-number" style="color: #6897bb;">3</span>, <span class="hljs-number" style="color: #6897bb;">4</span>];
<span class="hljs-keyword" style="color: #cc7832;">const</span> [first, second] = a;
<span class="hljs-built_in">console</span>.log(first); <span class="hljs-comment" style="color: grey;">// >> 1</span>
<span class="hljs-built_in">console</span>.log(second); <span class="hljs-comment" style="color: grey;">// >> 2</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> x = {a: <span class="hljs-string" style="color: #6a8759;">"foo"</span>, b: <span class="hljs-string" style="color: #6a8759;">"bar"</span>, c: <span class="hljs-number" style="color: #6897bb;">12</span>};
<span class="hljs-keyword" style="color: #cc7832;">const</span> {b, c} = x;
<span class="hljs-built_in">console</span>.log(b); <span class="hljs-comment" style="color: grey;">// >> bar</span>
<span class="hljs-built_in">console</span>.log(c); <span class="hljs-comment" style="color: grey;">// >> 12</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">f</span>(<span class="hljs-params">{a, b}</span>) </span>{
<span class="hljs-built_in">console</span>.log(a+<span class="hljs-string" style="color: #6a8759;">", "</span>+b);
}
f(x); <span class="hljs-comment" style="color: grey;">// >> foo, bar</span>
</pre><h3 id="mcetoc_1go3akel62se">Arraw functions</h3><ul><li>Arrow functions are a compact alternative to function expressions</li><li>If the body consists of a single expression, then the curly braces can be omitted and the return is implied</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">const</span> f = (a, b) => {
<span class="hljs-keyword" style="color: #cc7832;">const</span> c = a * a;
<span class="hljs-keyword" style="color: #cc7832;">return</span> c+b;
};
<span class="hljs-built_in">console</span>.log(f(<span class="hljs-number" style="color: #6897bb;">3</span>, <span class="hljs-number" style="color: #6897bb;">4</span>)); <span class="hljs-comment" style="color: grey;">// >> 13</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> g = a => a * a;
<span class="hljs-built_in">console</span>.log(g(<span class="hljs-number" style="color: #6897bb;">3</span>)); <span class="hljs-comment" style="color: grey;">// >> 9</span>
</pre><ul><li>Arrow functions cannot be bound to objects</li><li>The this reference is lexically scoped</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">const</span> alice = {
name: <span class="hljs-string" style="color: #6a8759;">"Alice"</span>,
friends: [<span class="hljs-string" style="color: #6a8759;">"Bob"</span>, <span class="hljs-string" style="color: #6a8759;">"Eve"</span>],
sayHi: <span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">this</span>.friends.forEach(friend => {
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword" style="color: #cc7832;">this</span>.name+<span class="hljs-string" style="color: #6a8759;">" says hi to "</span>+friend); <span class="hljs-comment" style="color: grey;">// this is lexically scoped</span>
});
}
};
<span class="hljs-keyword" style="color: #cc7832;">const</span> speak = phrase => <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword" style="color: #cc7832;">this</span>.name+<span class="hljs-string" style="color: #6a8759;">" says "</span>+phrase);
speak.call(alice, <span class="hljs-string" style="color: #6a8759;">"Hello World!"</span>); <span class="hljs-comment" style="color: grey;">// >> undefined says Hello World!</span>
</pre><h3 id="mcetoc_1go3akel62sf">Classes</h3><ul><li>The class keyword is syntactic sugar for constructor functions and prototype inheritance</li><li>A class may contain a constructor, the actual constructor function, which will be bound to the class name, and any number of methods</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-class"><span class="hljs-keyword" style="color: #cc7832;">class</span> <span class="hljs-title" style="color: #ffc66d;">Person</span> </span>{
<span class="hljs-keyword" style="color: #cc7832;">constructor</span>(name, age) {
<span class="hljs-keyword" style="color: #cc7832;">this</span>.name = name;
<span class="hljs-keyword" style="color: #cc7832;">this</span>.age = age;
}
speak(phrase) {
<span class="hljs-built_in">console</span>.log(<span class="hljs-string" style="color: #6a8759;">`<span class="hljs-subst">${this.name}</span> says: <span class="hljs-subst">${phrase}</span>`</span>);
}
}
<span class="hljs-keyword" style="color: #cc7832;">const</span> alice = <span class="hljs-keyword" style="color: #cc7832;">new</span> Person(<span class="hljs-string" style="color: #6a8759;">"Alice"</span>, <span class="hljs-number" style="color: #6897bb;">19</span>);
alice.speak(<span class="hljs-string" style="color: #6a8759;">"It's just syntactic sugar!"</span>);
</pre><h3 id="mcetoc_1go3akel62sg">Class Inheritance</h3><ul><li>Classes support inheritance</li><li>The super keyword is used to reference the constructor and methods defined in the base class</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-class"><span class="hljs-keyword" style="color: #cc7832;">class</span> <span class="hljs-title" style="color: #ffc66d;">Student</span> <span class="hljs-keyword" style="color: #cc7832;">extends</span> <span class="hljs-title" style="color: #ffc66d;">Person</span> </span>{
<span class="hljs-keyword" style="color: #cc7832;">constructor</span>(name, age, university) {
<span class="hljs-keyword" style="color: #cc7832;">super</span>(name, age);
<span class="hljs-keyword" style="color: #cc7832;">this</span>.university = university;
}
speak(phrase) {
<span class="hljs-keyword" style="color: #cc7832;">super</span>.speak(phrase);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string" style="color: #6a8759;">"And I'm a student at the "</span>+<span class="hljs-keyword" style="color: #cc7832;">this</span>.university);
}
}
</pre><h2 id="mcetoc_1go3akel62sh">Modules</h2><h3 id="mcetoc_1go3akel62si">Global Scope</h3><ul><li>JavaScript has one global scope</li><li>Different JavaScript files share the same global scope and have not their own private scope</li></ul><p><code>let counter = 0;</code><br><code>function count() { return ++counter; }</code><br><br><code>function logCounter() { console.log(counter); }</code><br><br><code><html></code><br><code><head></code><br><code><script src="listing_11a.js"></script></code><br><code><script src="listing_11b.js"></script></code><br><code></head></code><br><code><body></code><br><code><script></code><br><code>count();</code><br><code>logCounter(); // >> 1</code><br><code></script></code><br><code></body></code><br><code></html></code></p><h3 id="mcetoc_1go3akel62sj">IIFE</h3><ul><li>An immediately-invoked function expression (IIFE, pronounced ”iffy”) is an unnamed function which is immediately invoked</li><li>An IIFE takes advantage of the concept of closures and the local scope produced by functions</li><li>IIFEs can be used to implement a simple module pattern, in which each module binds only a single global variable</li></ul><p>counter-service.js:</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">const</span> counterService = (<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>() </span>{
<span class="hljs-comment" style="color: grey;">// Private scope</span>
<span class="hljs-keyword" style="color: #cc7832;">let</span> counter = <span class="hljs-number" style="color: #6897bb;">0</span>;
<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">count</span>() </span>{ <span class="hljs-keyword" style="color: #cc7832;">return</span> ++counter; }
<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">logCounter</span>() </span>{ <span class="hljs-built_in">console</span>.log(counter); }
<span class="hljs-comment" style="color: grey;">// Export public features</span>
<span class="hljs-keyword" style="color: #cc7832;">return</span> {count, logCounter};
})();
</pre><p><code><script src="counter-service.js"></script></code><br><code><script></code><br><code>counterService.count();</code><br><code>counterService.logCounter(); // 1</code><br><code></script></code></p><h3 id="mcetoc_1go3akel62sk">Example jQuery Plugin</h3><ul><li>A jQuery plugin is implemented as an IIFE</li><li>New features are added to the prototype of jQuery objects (which is the $.fn object)</li><li>See How to Create a Basic Plugin for more details</li></ul><p>jquery-identify.js;</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;">(<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>(<span class="hljs-params">$</span>) </span>{
<span class="hljs-keyword" style="color: #cc7832;">let</span> counter = <span class="hljs-number" style="color: #6897bb;">0</span>;
$.fn.identify = <span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">return</span> <span class="hljs-keyword" style="color: #cc7832;">this</span>.each(<span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">this</span>.id = <span class="hljs-string" style="color: #6a8759;">'id-'</span>+(++counter);
});
}
})(jQuery);
</pre><p><code><script src="jquery.js"></script></code><br><code><script src="jquery-identify.js"></script></code><br><code><script></code><br><code>$('p, img').identify();</code><br><code></script></code></p><h3 id="mcetoc_1go3r9h51351">Module Systems</h3><ul><li>Module Systems provide a private scope on a file basis with the possibility to export functionality and to import functionality from other modules</li><li>Before ES6, JavaScript had no built-in module system and proprietary module systems, such as CommonJS (which is still used by Node.js), were needed</li><li>ES6 introduced its own module system (often called ES modules) with the new keywords import and export</li><li>In larger applications, module dependencies are resolved during the build and bundling process</li><li>ES modules are natively supported by all modern browsers</li></ul><h3 id="mcetoc_1go3r9h51352">ES Modules</h3><ul><li>Features are exported from a module using the export keyword</li><li>The export keyword is placed in front of the item to export</li><li>Functions, classes and variables defined with let or const can be exported</li><li>Multiple features can be exported in a single statement by wrapping the comma-separated list of items in curly braces</li><li>Items which are not exported are local to the module</li><li>Features are imported from other modules using the import keyword</li><li>Specific features are imported by their names (comma-separated list in curly braces)</li><li>All features of a module can be important using the *-notation</li></ul><h3 id="mcetoc_1go3r9h51353">Export Examples</h3><p>math.js:</p><p><code>export const PI = computePI();</code><br><code>export function square(x) { return x * x; }</code><br><code>export function sum(x, y) { return x + y; }</code><br><code>// Local to math.js</code><br><code>function computePI() { return 3.14; }</code></p><p>colors.js:</p><p><code>const white = '#ffffff', black = '#000000';</code><br><code>function rgbToHex(r, g, b) { return '#' + toHex(r) + toHex(g) + toHex(b); }</code><br><code>function toHex(c) { return ('0' + c.toString(16)).slice(m2); }</code><br><code>// Export multiple features in a single statement</code><br><code>export {white, black, rgbToHex};</code></p><h3 id="mcetoc_1go3r9h51354">Import Examples</h3><p>file1.js:</p><p><code>// Import specific features from another module</code><br><code>import {square, PI} from 'math';</code><br><code>console.log(PI); // >> 3.14</code><br><code>console.log(square(4)); // >> 16</code><br><br>file2.js</p><p><code>// Import all features from another module</code><br><code>import * as math from 'math';</code><br><code>console.log(math.PI); // >> 3.14</code><br><code>console.log(math.sum(4, 5)); // >> 9</code></p><h3 id="mcetoc_1go3r9h51355">Default Export</h3><ul><li>One single export per module can be marked as default using the default keyword</li><li>The default feature is imported without curly braces and any name can be given</li><li>Especially convenient if only one feature is exported per module</li></ul><p>hello-world.js:</p><p><code>export default function() {</code><br><code>console.log("Hello World!");</code><br><code>}</code></p><p>any-class.js:</p><p><code>export default class {</code><br><code>// ...</code><br><code>}</code></p><p>main.js:</p><p><code>import logHelloWorld from 'hello-world';</code><br><code>import AnyClass from 'any-class';</code><br><code>logHelloWorld();</code><br><code>let obj = new AnyClass();</code></p><h3 id="mcetoc_1go3r9h51356">Usage in the Browser</h3><ul><li>The type of the script must be module</li><li>Modules are loaded deferred (after the browser finished parsing the HTML and building the DOM)</li><li>Modules are running in strict mode by default</li><li>The module name must be the file path relative to the site root or, using the dot-syntax, relative to the current location, e.g.: import ... from './lib/my-module.js';</li></ul><p><code><html></code><br><code><head></code><br><code><title>ES Modules</title></code><br><code><script type="module" src="main.js"></script></code><br><code><script type="module"></code><br><code>import {PI} from './math.js';</code><br><code>// ...</code><br><code></script></code><br><code></head></code><br><code><body> ... </body></code><br><code></html></code></p><h2 id="mcetoc_1go3akel62sl">Promises</h2><h3 id="mcetoc_1go41qk9o3km">Asynchronous Programming</h3><ul><li>JavaScript is single-threaded, hence time-consuming tasks must be implemented asynchronously to not block the thread</li><li>Promises are helpers for asynchronous programming</li><li>A promise is a proxy for a value possibly known in the future</li><li>Instead of passing callback functions to the asynchronous function, the synchronous function returns a promise on which success and error handlers can be registered</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-comment" style="color: grey;">// Traditional approach with callbacks passed to the asynchronous function</span>
computeAsync(<span class="hljs-string" style="color: #6a8759;">"Foo"</span>, <span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>(<span class="hljs-params">result</span>) </span>{
<span class="hljs-comment" style="color: grey;">// Process result</span>
}, <span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span>(<span class="hljs-params">error</span>) </span>{
<span class="hljs-comment" style="color: grey;">// Handle error</span>
});
<span class="hljs-comment" style="color: grey;">// Promise based approach where the asynchronous function returns a promise</span>
computeAsync(<span class="hljs-string" style="color: #6a8759;">"Foo"</span>)
.then(result => { <span class="hljs-comment" style="color: grey;">/* Process result */</span> })
.catch(error => { <span class="hljs-comment" style="color: grey;">/* Handle error */</span> });
</pre><h3 id="mcetoc_1go41qk9o3kn">Promises Are State Machines</h3><ul><li>Newly created promises are in the state pending</li><li>A promise remains pending as long as the value is unknown and no error has occurred</li><li>As soon as the value is available, the state changes to fullfiled and registered success handlers are called</li><li>If an error occurs, the state changes to rejected and registered error handlers are called</li><li>Once the state is fullfiled or rejected, the promise remains in this state for ever</li></ul><figure class="post__image"><img loading="lazy" src="https://www.finecloud.ch/media/posts/79/Screenshot-2023-01-31-at-14.42.22.png" alt="" width="882" height="734" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-xs.png 300w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-sm.png 480w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-md.png 768w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-lg.png 1024w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-xl.png 1360w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.42.22-2xl.png 1600w"></figure><h2 id="mcetoc_1go41qk9o3ko">Creating Promises</h2><ul><li>Promises are created using the Promise constructor</li><li>A function is passed to the constructor implementing the asynchronous task</li><li>The function is called by the promise, passing two functions to resolve or reject the promise</li><li>Either the resolve or reject function must be finally called by the asynchronous task</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">computeAsync</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">return</span> <span class="hljs-keyword" style="color: #cc7832;">new</span> <span class="hljs-built_in">Promise</span>((resolve, reject) => {
<span class="hljs-comment" style="color: grey;">// ... Perform the asynchronous task (Promise is pending)</span>
<span class="hljs-keyword" style="color: #cc7832;">if</span> (success) resolve(result); <span class="hljs-comment" style="color: grey;">// Promise will be fulfilled</span>
<span class="hljs-keyword" style="color: #cc7832;">else</span> reject(error); <span class="hljs-comment" style="color: grey;">// Promise will be rejected</span>
});
}
</pre><h3 id="mcetoc_1go41qk9o3kp">Promise Example</h3><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">computePI</span>() </span>{
<span class="hljs-keyword" style="color: #cc7832;">return</span> <span class="hljs-keyword" style="color: #cc7832;">new</span> <span class="hljs-built_in">Promise</span>((resolve, reject) => {
<span class="hljs-comment" style="color: grey;">// Computing PI is hard work...</span>
setTimeout(() => {
<span class="hljs-comment" style="color: grey;">// Computing PI fails with a certain probability...</span>
<span class="hljs-keyword" style="color: #cc7832;">if</span> (<span class="hljs-built_in">Math</span>.random() < <span class="hljs-number" style="color: #6897bb;">0.2</span>) {
reject(<span class="hljs-string" style="color: #6a8759;">"Sorry, computation failed!"</span>); <span class="hljs-comment" style="color: grey;">// Reject the promise</span>
} <span class="hljs-keyword" style="color: #cc7832;">else</span> {
resolve(<span class="hljs-number" style="color: #6897bb;">3.14</span>); <span class="hljs-comment" style="color: grey;">// Resolve the promise to the value of PI</span>
}
}, <span class="hljs-number" style="color: #6897bb;">300</span>);
});
}
computePI()
.then(result => <span class="hljs-built_in">console</span>.log(<span class="hljs-string" style="color: #6a8759;">"PI: "</span>+result))
.catch(error => <span class="hljs-built_in">console</span>.log(error));
</pre><h3 id="mcetoc_1go41qk9o3kq">Chaining</h3><ul><li>The then and catch functions return a promise, hence they can<br>be chained</li><li>The promise returned by then and catch resolves to the return value of the handler or to its original settled value if the handler was not called (e.g. a catch-handler is not called on a fullfiled promise)</li><li>If the handler returns a promise, the promise returned by then and catch resolves to the same value as the returned promise</li></ul><figure class="post__image"><img loading="lazy" src="https://www.finecloud.ch/media/posts/79/Screenshot-2023-01-31-at-14.49.16.png" alt="" width="2062" height="734" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-xs.png 300w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-sm.png 480w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-md.png 768w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-lg.png 1024w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-xl.png 1360w, https://www.finecloud.ch/media/posts/79/responsive/Screenshot-2023-01-31-at-14.49.16-2xl.png 1600w"></figure><h3 id="mcetoc_1go41qk9o3kr">Chaining and Combining Examples</h3><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-comment" style="color: grey;">// Chaining</span>
doAsync()
.then(resultA => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.then(resultB => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.catch(error => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.then(resultC => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.catch(error => { <span class="hljs-comment" style="color: grey;">/* ... */</span> });
<span class="hljs-comment" style="color: grey;">// Add multiple handlers to the same promise</span>
<span class="hljs-keyword" style="color: #cc7832;">const</span> promise = doAsync();
promise.then(result => { <span class="hljs-comment" style="color: grey;">/* ... */</span> });
promise.then(result => { <span class="hljs-comment" style="color: grey;">/* ... */</span> });
<span class="hljs-comment" style="color: grey;">// 'Wait' until all promises are fulfilled or one rejected</span>
<span class="hljs-built_in">Promise</span>.all([doAsync(<span class="hljs-string" style="color: #6a8759;">"A"</span>), doAsync(<span class="hljs-string" style="color: #6a8759;">"B"</span>), doAsync2()])
.then(results => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.catch(error => { <span class="hljs-comment" style="color: grey;">/* ... */</span> });
<span class="hljs-comment" style="color: grey;">// 'Wait' until the first promise is fulfilled or rejected</span>
<span class="hljs-built_in">Promise</span>.race([doAsync(<span class="hljs-string" style="color: #6a8759;">"A"</span>), doAsync(<span class="hljs-string" style="color: #6a8759;">"B"</span>), doAsync2()])
.then(result => { <span class="hljs-comment" style="color: grey;">/* ... */</span> })
.catch(error => { <span class="hljs-comment" style="color: grey;">/* ... */</span> });
</pre><h3 id="mcetoc_1go41qk9o3ks">async and await</h3><ul><li>async and await allow asynchronous code to be written synchronously</li><li>An async function implicitly returns a promise, which resolves to the return value of the function or is rejected on exception</li><li>async functions can await other promises (written synchronously)</li><li>await interrupts the synchronous execution and waits until the returned promise is resolved or rejected</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">async</span> <span class="hljs-function"><span class="hljs-keyword" style="color: #cc7832;">function</span> <span class="hljs-title" style="color: #ffc66d;">computeDiskArea</span>(<span class="hljs-params">radius</span>) </span>{
<span class="hljs-keyword" style="color: #cc7832;">const</span> PI = <span class="hljs-keyword" style="color: #cc7832;">await</span> computePI();
<span class="hljs-keyword" style="color: #cc7832;">return</span> radius * radius * PI;
}
computeDiskArea(<span class="hljs-number" style="color: #6897bb;">2</span>)
.then(area => <span class="hljs-built_in">console</span>.log(<span class="hljs-string" style="color: #6a8759;">"The area of a disk with r=2 is "</span>+area))
.catch(error => <span class="hljs-built_in">console</span>.log(<span class="hljs-string" style="color: #6a8759;">"An error occurred: "</span>+error))
</pre><h2 id="mcetoc_1go3akel62sm">Fetch API</h2><ul><li>The Fetch API provides an interface for fetching resources</li><li>This includes resources across the network</li><li>It is similar to the XMLHttpRequest but it is more powerful and more flexible</li><li>It provides a generic definition of Request and Response objects</li><li>The global fetch function takes the URL of a resource as parameter and returns a promise which resolves to a Response object once the response is available</li></ul><p><code>fetch('http://quotes.org')</code><br><code> .then(response => response.text())</code><br><code> .then(quote => console.log(quote));</code></p><h3>Response Object</h3><ul><li>A Response object has the following properties:<ul><li>ok - true if the status code is 2xx, false otherwise</li><li>status - the response status code</li><li>statusText - the status code message</li><li>headers - the response headers</li></ul></li><li>In addition, Response provides the following methods:<ul><li>text() returns a promise resolving to the body as string</li><li>json() returns a promise resolving to the result of parsing the body as JSON</li><li>blob() returns a promise resolving the body as Blob object</li></ul></li></ul><p><code>fetch('http://news.org')</code><br><code> .then(response => response.json())</code><br><code> .then(data => data.articles.forEach(article => console.log(article.title)));</code></p><h3>Request Options</h3><p>The fetch function has as a second optional parameter that allows setting the HTTP method, headers and request body:</p><p><code>fetch('http://news.org', {</code><br><code>method: 'POST',</code><br><code>headers: {</code><br><code>'Authorization:': 'Basic amRAZXhhbXBsZS5vcmc6MTIzNDU=',</code><br><code>'Content-Type': 'application/json'</code><br><code>},</code><br><code>body: JSON.stringify(article)</code><br><code>});</code></p><p>Advanced settings include:</p><ul><li>the interaction with the browser cache</li><li>the following of redirect responses</li><li>sending credentials</li><li>aborting requests</li></ul><h3>Error Handling</h3><ul><li>The promise returned by fetch does only reject on network errors but not on HTTP errors such as 404 or 500 (in contrast to many AJAX libraries)</li><li>An accurate error handling should check if the promise was resolved and if its status is OK</li></ul><pre class="hljs" style="color: #a9b7c6; background: #282b2e; display: block; overflow-x: auto; padding: 0.5em;">fetch(<span class="hljs-string" style="color: #6a8759;">'http://news.org'</span>)
.then(response => {
<span class="hljs-keyword" style="color: #cc7832;">if</span> (!response.ok)
<span class="hljs-comment" style="color: grey;">// Error handling based on HTTP status</span>
<span class="hljs-keyword" style="color: #cc7832;">return</span> response.json();
})
.then(data => {
...
})
.catch(error => {
<span class="hljs-comment" style="color: grey;">// Error handling (network error, JSON syntax error, etc.)</span>
});
</pre><p> </p></div><footer class="wrapper post__footer"><p class="post__last-updated">This article was updated on März 29, 2023</p><ul class="post__tag"><li><a href="https://www.finecloud.ch/tags/javascript/">javascript</a></li><li><a href="https://www.finecloud.ch/tags/softwareentwicklung/">software development</a></li></ul><div class="post__share"></div></footer></article><nav class="post__nav"><div class="post__nav-inner"><div class="post__nav-prev"><svg width="1.041em" height="0.416em" aria-hidden="true"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#arrow-prev"/></svg> <a href="https://www.finecloud.ch/javascript-and-the-browser.html" class="post__nav-link" rel="prev"><span>Previous</span> JavaScript and the browser</a></div><div class="post__nav-next"><a href="https://www.finecloud.ch/cleancode.html" class="post__nav-link" rel="next"><span>Next</span> CleanCode </a><svg width="1.041em" height="0.416em" aria-hidden="true"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#arrow-next"/></svg></div></div></nav><div class="post__related related"><div class="wrapper"><h2 class="h5 related__title">You should also read:</h2><article class="related__item"><div class="feed__meta"><time datetime="2023-01-24T08:35" class="feed__date">Januar 24, 2023</time></div><h3 class="h1"><a href="https://www.finecloud.ch/javascript-and-the-browser.html">JavaScript and the browser</a></h3></article><article class="related__item"><div class="feed__meta"><time datetime="2023-01-17T20:13" class="feed__date">Januar 17, 2023</time></div><h3 class="h1"><a href="https://www.finecloud.ch/javascript-objects.html">JavaScript objects</a></h3></article><article class="related__item"><div class="feed__meta"><time datetime="2023-01-17T19:48" class="feed__date">Januar 17, 2023</time></div><h3 class="h1"><a href="https://www.finecloud.ch/javascript-arrays.html">JavaScript arrays</a></h3></article></div></div></main><footer class="footer"><div class="footer__copyright"><p>Powered by Publii</p></div><button onclick="backToTopFunction()" id="backToTop" class="footer__bttop" aria-label="Back to top" title="Back to top"><svg><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#toparrow"/></svg></button></footer></div><script>window.publiiThemeMenuConfig = {
mobileMenuMode: 'sidebar',
animationSpeed: 300,
submenuWidth: 'auto',
doubleClickTime: 500,
mobileMenuExpandableSubmenus: true,
relatedContainerForOverlayMenuSelector: '.top',
};</script><script defer="defer" src="https://www.finecloud.ch/assets/js/scripts.min.js?v=6ca8b60e6534a3888de1205e82df8528"></script><script>var images = document.querySelectorAll('img[loading]');
for (var i = 0; i < images.length; i++) {
if (images[i].complete) {
images[i].classList.add('is-loaded');
} else {
images[i].addEventListener('load', function () {
this.classList.add('is-loaded');
}, false);
}
}</script><script defer="defer" src="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism.js"></script></body></html>