-
Notifications
You must be signed in to change notification settings - Fork 529
/
es6_cheat_sheet.txt
executable file
·1196 lines (916 loc) · 29 KB
/
es6_cheat_sheet.txt
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# es6-cheatsheet
A cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code
snippet examples for your day to day workflow. Contributions are welcome!
## Table of Contents
- [var versus let / const](#var-versus-let--const)
- [Replacing IIFEs with Blocks](#replacing-iifes-with-blocks)
- [Arrow Functions](#arrow-functions)
- [Strings](#strings)
- [Destructuring](#destructuring)
- [Modules](#modules)
- [Parameters](#parameters)
- [Classes](#classes)
- [Symbols](#symbols)
- [Maps](#maps)
- [WeakMaps](#weakmaps)
- [Promises](#promises)
- [Generators](#generators)
- [Async Await](#async-await)
- [Getter/Setter functions](#getter-and-setter-functions)
## var versus let / const
> Besides `var`, we now have access to two new identifiers for storing values
—`let` and `const`. Unlike `var`, `let` and `const` statements are not hoisted
to the top of their enclosing scope.
An example of using `var`:
```javascript
var snack = 'Meow Mix';
function getFood(food) {
if (food) {
var snack = 'Friskies';
return snack;
}
return snack;
}
getFood(false); // undefined
```
However, observe what happens when we replace `var` using `let`:
```javascript
let snack = 'Meow Mix';
function getFood(food) {
if (food) {
let snack = 'Friskies';
return snack;
}
return snack;
}
getFood(false); // 'Meow Mix'
```
This change in behavior highlights that we need to be careful when refactoring
legacy code which uses `var`. Blindly replacing instances of `var` with `let`
may lead to unexpected behavior.
> **Note**: `let` and `const` are block scoped. Therefore, referencing
block-scoped identifiers before they are defined will produce
a `ReferenceError`.
```javascript
console.log(x); // ReferenceError: x is not defined
let x = 'hi';
```
> **Best Practice**: Leave `var` declarations inside of legacy code to denote
that it needs to be carefully refactored. When working on a new codebase, use
`let` for variables that will change their value over time, and `const` for
variables which cannot be reassigned.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Replacing IIFEs with Blocks
> A common use of **Immediately Invoked Function Expressions** is to enclose
values within its scope. In ES6, we now have the ability to create block-based
scopes and therefore are not limited purely to function-based scope.
```javascript
(function () {
var food = 'Meow Mix';
}());
console.log(food); // Reference Error
```
Using ES6 Blocks:
```javascript
{
let food = 'Meow Mix';
};
console.log(food); // Reference Error
```
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Arrow Functions
Often times we have nested functions in which we would like to preserve the
context of `this` from its lexical scope. An example is shown below:
```javascript
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character; // Cannot read property 'name' of undefined
});
};
```
One common solution to this problem is to store the context of `this` using
a variable:
```javascript
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
var that = this; // Store the context of this
return arr.map(function (character) {
return that.name + character;
});
};
```
We can also pass in the proper context of `this`:
```javascript
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character;
}, this);
};
```
As well as bind the context:
```javascript
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character;
}.bind(this));
};
```
Using **Arrow Functions**, the lexical value of `this` isn't shadowed and we
can re-write the above as shown:
```javascript
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(character => this.name + character);
};
```
> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the
lexical value of `this`.
Arrow Functions are also more concise when used in function expressions which
simply return a value:
```javascript
var squares = arr.map(function (x) { return x * x }); // Function Expression
```
```javascript
const arr = [1, 2, 3, 4, 5];
const squares = arr.map(x => x * x); // Arrow Function for terser implementation
```
> **Best Practice**: Use **Arrow Functions** in place of function expressions
when possible.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Strings
With ES6, the standard library has grown immensely. Along with these changes
are new methods which can be used on strings, such as `.includes()` and
`.repeat()`.
### .includes( )
```javascript
var string = 'food';
var substring = 'foo';
console.log(string.indexOf(substring) > -1);
```
Instead of checking for a return value `> -1` to denote string containment,
we can simply use `.includes()` which will return a boolean:
```javascript
const string = 'food';
const substring = 'foo';
console.log(string.includes(substring)); // true
```
### .repeat( )
```javascript
function repeat(string, count) {
var strings = [];
while(strings.length < count) {
strings.push(string);
}
return strings.join('');
}
```
In ES6, we now have access to a terser implementation:
```javascript
// String.repeat(numberOfRepetitions)
'meow'.repeat(3); // 'meowmeowmeow'
```
### Template Literals
Using **Template Literals**, we can now construct strings that have special
characters in them without needing to escape them explicitly.
```javascript
var text = "This string contains \"double quotes\" which are escaped.";
```
```javascript
let text = `This string contains "double quotes" which don't need to be escaped anymore.`;
```
**Template Literals** also support interpolation, which makes the task of
concatenating strings and values:
```javascript
var name = 'Tiger';
var age = 13;
console.log('My cat is named ' + name + ' and is ' + age + ' years old.');
```
Much simpler:
```javascript
const name = 'Tiger';
const age = 13;
console.log(`My cat is named ${name} and is ${age} years old.`);
```
In ES5, we handled new lines as follows:
```javascript
var text = (
'cat\n' +
'dog\n' +
'nickelodeon'
);
```
Or:
```javascript
var text = [
'cat',
'dog',
'nickelodeon'
].join('\n');
```
**Template Literals** will preserve new lines for us without having to
explicitly place them in:
```javascript
let text = ( `cat
dog
nickelodeon`
);
```
**Template Literals** can accept expressions, as well:
```javascript
let today = new Date();
let text = `The time and date is ${today.toLocaleString()}`;
```
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Destructuring
Destructuring allows us to extract values from arrays and objects (even deeply
nested) and store them in variables with a more convenient syntax.
### Destructuring Arrays
```javascript
var arr = [1, 2, 3, 4];
var a = arr[0];
var b = arr[1];
var c = arr[2];
var d = arr[3];
```
```javascript
let [a, b, c, d] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 2
```
### Destructuring Objects
```javascript
var luke = { occupation: 'jedi', father: 'anakin' };
var occupation = luke.occupation; // 'jedi'
var father = luke.father; // 'anakin'
```
```javascript
let luke = { occupation: 'jedi', father: 'anakin' };
let {occupation, father} = luke;
console.log(occupation); // 'jedi'
console.log(father); // 'anakin'
```
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Modules
Prior to ES6, we used libraries such as [Browserify](http://browserify.org/)
to create modules on the client-side, and [require](https://nodejs.org/api/modules.html#modules_module_require_id)
in **Node.js**. With ES6, we can now directly use modules of all types
(AMD and CommonJS).
### Exporting in CommonJS
```javascript
module.exports = 1;
module.exports = { foo: 'bar' };
module.exports = ['foo', 'bar'];
module.exports = function bar () {};
```
### Exporting in ES6
With ES6, we have various flavors of exporting. We can perform
**Named Exports**:
```javascript
export let name = 'David';
export let age = 25;
```
As well as **exporting a list** of objects:
```javascript
function sumTwo(a, b) {
return a + b;
}
function sumThree(a, b, c) {
return a + b + c;
}
export { sumTwo, sumThree };
```
We can also export functions, objects and values (etc.) simply by using the `export` keyword:
```javascript
export function sumTwo(a, b) {
return a + b;
}
export function sumThree(a, b, c) {
return a + b + c;
}
```
And lastly, we can **export default bindings**:
```javascript
function sumTwo(a, b) {
return a + b;
}
function sumThree(a, b, c) {
return a + b + c;
}
let api = {
sumTwo,
sumThree
};
export default api;
/* Which is the same as
* export { api as default };
*/
```
> **Best Practices**: Always use the `export default` method at **the end** of
the module. It makes it clear what is being exported, and saves time by having
to figure out what name a value was exported as. More so, the common practice
in CommonJS modules is to export a single value or object. By sticking to this
paradigm, we make our code easily readable and allow ourselves to interpolate
between CommonJS and ES6 modules.
### Importing in ES6
ES6 provides us with various flavors of importing. We can import an entire file:
```javascript
import 'underscore';
```
> It is important to note that simply **importing an entire file will execute
all code at the top level of that file**.
Similar to Python, we have named imports:
```javascript
import { sumTwo, sumThree } from 'math/addition';
```
We can also rename the named imports:
```javascript
import {
sumTwo as addTwoNumbers,
sumThree as sumThreeNumbers
} from 'math/addition';
```
In addition, we can **import all the things** (also called namespace import):
```javascript
import * as util from 'math/addition';
```
Lastly, we can import a list of values from a module:
```javascript
import * as additionUtil from 'math/addition';
const { sumTwo, sumThree } = additionUtil;
```
Importing from the default binding like this:
```javascript
import api from 'math/addition';
// Same as: import { default as api } from 'math/addition';
```
While it is better to keep the exports simple, but we can sometimes mix default import and mixed import if needed.
When we are exporting like this:
```javascript
// foos.js
export { foo as default, foo1, foo2 };
```
We can import them like the following:
```javascript
import foo, { foo1, foo2 } from 'foos';
```
When importing a module exported using commonjs syntax (such as React) we can do:
```javascript
import React from 'react';
const { Component, PropTypes } = React;
```
This can also be simplified further, using:
```javascript
import React, { Component, PropTypes } from 'react';
```
> **Note**: Values that are exported are **bindings**, not references.
Therefore, changing the binding of a variable in one module will affect the
value within the exported module. Avoid changing the public interface of these
exported values.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Parameters
In ES5, we had varying ways to handle functions which needed **default values**,
**indefinite arguments**, and **named parameters**. With ES6, we can accomplish
all of this and more using more concise syntax.
### Default Parameters
```javascript
function addTwoNumbers(x, y) {
x = x || 0;
y = y || 0;
return x + y;
}
```
In ES6, we can simply supply default values for parameters in a function:
```javascript
function addTwoNumbers(x=0, y=0) {
return x + y;
}
```
```javascript
addTwoNumbers(2, 4); // 6
addTwoNumbers(2); // 2
addTwoNumbers(); // 0
```
### Rest Parameters
In ES5, we handled an indefinite number of arguments like so:
```javascript
function logArguments() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
```
Using the **rest** operator, we can pass in an indefinite amount of arguments:
```javascript
function logArguments(...args) {
for (let arg of args) {
console.log(arg);
}
}
```
### Named Parameters
One of the patterns in ES5 to handle named parameters was to use the **options
object** pattern, adopted from jQuery.
```javascript
function initializeCanvas(options) {
var height = options.height || 600;
var width = options.width || 400;
var lineStroke = options.lineStroke || 'black';
}
```
We can achieve the same functionality using destructuring as a formal parameter
to a function:
```javascript
function initializeCanvas(
{ height=600, width=400, lineStroke='black'}) {
// Use variables height, width, lineStroke here
}
```
If we want to make the entire value optional, we can do so by destructuring an
empty object:
```javascript
function initializeCanvas(
{ height=600, width=400, lineStroke='black'} = {}) {
// ...
}
```
### Spread Operator
In ES5, we could find the max of values in an array by using the `apply` method on `Math.max` like this:
```javascript
Math.max.apply(null, [-1, 100, 9001, -32]); // 9001
```
In ES6, we can now use the spread operator to pass an array of values to be used as
parameters to a function:
```javascript
Math.max(...[-1, 100, 9001, -32]); // 9001
```
We can concat array literals easily with this intuitive syntax:
```javascript
let cities = ['San Francisco', 'Los Angeles'];
let places = ['Miami', ...cities, 'Chicago']; // ['Miami', 'San Francisco', 'Los Angeles', 'Chicago']
```
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Classes
Prior to ES6, we implemented Classes by creating a constructor function and
adding properties by extending the prototype:
```javascript
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.incrementAge = function () {
return this.age += 1;
};
```
And created extended classes by the following:
```javascript
function Personal(name, age, gender, occupation, hobby) {
Person.call(this, name, age, gender);
this.occupation = occupation;
this.hobby = hobby;
}
Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
Person.prototype.incrementAge.call(this);
this.age += 20;
console.log(this.age);
};
```
ES6 provides much needed syntactic sugar for doing this under the hood. We can
create Classes directly:
```javascript
class Person {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
incrementAge() {
this.age += 1;
}
}
```
And extend them using the `extends` keyword:
```javascript
class Personal extends Person {
constructor(name, age, gender, occupation, hobby) {
super(name, age, gender);
this.occupation = occupation;
this.hobby = hobby;
}
incrementAge() {
super.incrementAge();
this.age += 20;
console.log(this.age);
}
}
```
> **Best Practice**: While the syntax for creating classes in ES6 obscures how
implementation and prototypes work under the hood, it is a good feature for
beginners and allows us to write cleaner code.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Symbols
Symbols have existed prior to ES6, but now we have a public interface to using
them directly. Symbols are immutable and unique and can be used as keys in any hash.
### Symbol( )
Calling `Symbol()` or `Symbol(description)` will create a unique symbol that cannot be looked up
globally. A Use case for `Symbol()` is to patch objects or namespaces from third parties with your own
logic, but be confident that you won't collide with updates to that library. For example,
if you wanted to add a method `refreshComponent` to the `React.Component` class, and be certain that
you didn't trample a method they add in a later update:
```javascript
const refreshComponent = Symbol();
React.Component.prototype[refreshComponent] = () => {
// do something
}
```
### Symbol.for(key)
`Symbol.for(key)` will create a Symbol that is still immutable and unique, but can be looked up globally.
Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for
`Symbol(description)`:
```javascript
Symbol('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol.for('foo') // true
```
A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be
achieved by having your code look for a Symbol member on object arguments from third parties that contain some
known interface. For example:
```javascript
function reader(obj) {
const specialRead = Symbol.for('specialRead');
if (obj[specialRead]) {
const reader = obj[specialRead]();
// do something with reader
} else {
throw new TypeError('object cannot be read');
}
}
```
And then in another library:
```javascript
const specialRead = Symbol.for('specialRead');
class SomeReadableType {
[specialRead]() {
const reader = createSomeReaderFrom(this);
return reader;
}
}
```
> A notable example of Symbol use for interoperability is `Symbol.iterator` which exists on all iterable
types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator
interface.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Maps
**Maps** is a much needed data structure in JavaScript. Prior to ES6, we created
**hash** maps through objects:
```javascript
var map = new Object();
map[key1] = 'value1';
map[key2] = 'value2';
```
However, this does not protect us from accidentally overriding functions with
specific property names:
```javascript
> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');
> TypeError: Property 'hasOwnProperty' is not a function
```
Actual **Maps** allow us to `set`, `get` and `search` for values (and much more).
```javascript
let map = new Map();
> map.set('name', 'david');
> map.get('name'); // david
> map.has('name'); // true
```
The most amazing part of Maps is that we are no longer limited to just using
strings. We can now use any type as a key, and it will not be type-cast to
a string.
```javascript
let map = new Map([
['name', 'david'],
[true, 'false'],
[1, 'one'],
[{}, 'object'],
[function () {}, 'function']
]);
for (let key of map.keys()) {
console.log(typeof key);
// > string, boolean, number, object, function
}
```
> **Note**: Using non-primitive values such as functions or objects won't work
when testing equality using methods such as `map.get()`. As such, stick to
primitive values such as Strings, Booleans and Numbers.
We can also iterate over maps using `.entries()`:
```javascript
for (let [key, value] of map.entries()) {
console.log(key, value);
}
```
<sup>[(back to table of contents)](#table-of-contents)</sup>
## WeakMaps
In order to store private data versions < ES6, we had various ways of doing this.
One such method was using naming conventions:
```javascript
class Person {
constructor(age) {
this._age = age;
}
_incrementAge() {
this._age += 1;
}
}
```
But naming conventions can cause confusion in a codebase and are not always
going to be upheld. Instead, we can use WeakMaps to store our values:
```javascript
let _age = new WeakMap();
class Person {
constructor(age) {
_age.set(this, age);
}
incrementAge() {
let age = _age.get(this) + 1;
_age.set(this, age);
if (age > 50) {
console.log('Midlife crisis');
}
}
}
```
The cool thing about using WeakMaps to store our private data is that their
keys do not give away the property names, which can be seen by using
`Reflect.ownKeys()`:
```javascript
> const person = new Person(50);
> person.incrementAge(); // 'Midlife crisis'
> Reflect.ownKeys(person); // []
```
A more practical example of using WeakMaps is to store data which is associated
to a DOM element without having to pollute the DOM itself:
```javascript
let map = new WeakMap();
let el = document.getElementById('someElement');
// Store a weak reference to the element with a key
map.set(el, 'reference');
// Access the value of the element
let value = map.get(el); // 'reference'
// Remove the reference
el.parentNode.removeChild(el);
el = null;
// map is empty, since the element is destroyed
```
As shown above, once the object is destroyed by the garbage collector,
the WeakMap will automatically remove the key-value pair which was identified
by that object.
> **Note**: To further illustrate the usefulness of this example, consider how
jQuery stores a cache of objects corresponding to DOM elements which have
references. Using WeakMaps, jQuery can automatically free up any memory that
was associated with a particular DOM element once it has been removed from the
document. In general, WeakMaps are very useful for any library that wraps DOM
elements.
<sup>[(back to table of contents)](#table-of-contents)</sup>
## Promises
Promises allow us to turn our horizontal code (callback hell):
```javascript
func1(function (value1) {
func2(value1, function (value2) {
func3(value2, function (value3) {
func4(value3, function (value4) {
func5(value4, function (value5) {
// Do something with value 5
});
});
});
});
});
```
Into vertical code:
```javascript
func1(value1)
.then(func2)
.then(func3)
.then(func4)
.then(func5, value5 => {
// Do something with value 5
});
```
Prior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or
[Q](https://github.com/kriskowal/q). Now we have Promises natively:
```javascript
new Promise((resolve, reject) =>
reject(new Error('Failed to fulfill Promise')))
.catch(reason => console.log(reason));
```
Where we have two handlers, **resolve** (a function called when the Promise is
**fulfilled**) and **reject** (a function called when the Promise is **rejected**).
> **Benefits of Promises**: Error Handling using a bunch of nested callbacks
can get chaotic. Using Promises, we have a clear path to bubbling errors up
and handling them appropriately. Moreover, the value of a Promise after it has
been resolved/rejected is immutable - it will never change.
Here is a practical example of using Promises:
```javascript
var request = require('request');
return new Promise((resolve, reject) => {
request.get(url, (error, response, body) => {
if (body) {
resolve(JSON.parse(body));
} else {
resolve({});
}
});
});
```
We can also **parallelize** Promises to handle an array of asynchronous
operations by using `Promise.all()`:
```javascript
let urls = [
'/api/commits',
'/api/issues/opened',
'/api/issues/assigned',
'/api/issues/completed',
'/api/issues/comments',
'/api/pullrequests'
];
let promises = urls.map((url) => {
return new Promise((resolve, reject) => {
$.ajax({ url: url })
.done((data) => {
resolve(data);
});
});
});
Promise.all(promises)
.then((results) => {
// Do something with results of all our promises