Skip to content

Commit d6a4892

Browse files
committed
Improve “Idempotent JavaScript Operations”
1 parent 0c8e815 commit d6a4892

File tree

1 file changed

+59
-31
lines changed

1 file changed

+59
-31
lines changed

lib/components_guide_web/templates/robust_javascript_interactivity/idempotent-javascript-operations.html.md

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,77 @@ Here I’m going to use the example of an online video service like Netflix, whe
77

88
## Adding and removing a show from a user’s list
99

10-
Before, using an Array:
10+
Apps like Netflix allow you to add a show to a list to watch later. If you’re like me, you rarely get around to actually watching them.
11+
12+
To implement this, we could use an array that holds all the show IDs like so:
1113

1214
```js
13-
const myList = [];
15+
const watchLater = [];
1416

1517
function add(showID) {
16-
myList.push(showID);
18+
watchLater.push(showID);
19+
console.log(watchLater);
1720
}
1821

1922
add(123);
23+
// [123]
24+
```
25+
26+
However, there’s an issue when we add the same item twice:
27+
28+
```js
2029
add(123);
21-
myList;
22-
// Appears twice, not idempotent :(
30+
add(123);
31+
// The same show ID appears twice :(
2332
// [123, 123]
2433
```
2534

26-
After, using a Set:
35+
We could fix this by adding logic to detect whether the item is already in the array, and skip adding it if so:
36+
37+
```js
38+
function add(showID) {
39+
if (watchLater.includes(showID)) {
40+
return;
41+
}
42+
43+
watchLater.push(showID);
44+
console.log(watchLater);
45+
}
46+
```
47+
48+
But wouldn’t it be great if we had a simpler solution? It’s annoying to have to think of these edge cases and code around them.
49+
50+
If we change our data structure to one that enforces uniqueness from the beginning, then our double entry problem is solved.
51+
52+
In JavaScript, a `Set` is a data structure that is ordered just like an array, but it enforces uniqueness:
2753

2854
```js
29-
const myList = new Set();
55+
const watchLater = new Set();
3056

3157
function add(showID) {
32-
myList.add(showID);
58+
watchLater.add(showID);
59+
console.log(watchLater);
3360
}
3461

3562
add(123);
3663
add(123);
37-
myList;
38-
// Appears once, is idempotent :)
64+
// Appears only once :)
3965
// Set { 123 }
4066
```
4167

4268
We can extend this for also removing an item from the list:
4369

4470
```js
45-
const myList = new Set();
71+
const watchLater = new Set();
4672

4773
function add(showID) {
48-
myList.add(showID);
74+
watchLater.add(showID);
75+
console.log(watchLater);
4976
}
5077

5178
function remove(showID) {
52-
myList.delete(showID);
79+
watchLater.delete(showID);
80+
console.log(watchLater);
5381
}
5482

5583
add(123);
@@ -62,43 +90,43 @@ remove(123);
6290
// Set {}
6391
```
6492

65-
As a bonus, we can add change tracking which would allow us to detect whether the data has actually changed, and if a consumer say needed to update or re-render.
93+
As a bonus, we can add change tracking which would allow us to detect whether the data has actually changed, and and if not, then avoid say a re-render.
6694

6795
```js
68-
const myList = new Set();
69-
let myListChangeCount = 0;
96+
const watchLater = new Set();
97+
let watchLaterChangeCount = 0;
7098

7199
function add(showID) {
72-
const before = myList.size;
73-
myList.add(showID);
100+
const before = watchLater.size;
101+
watchLater.add(showID);
74102

75-
if (myList.size > before) {
76-
myListChangeCount++;
103+
if (watchLater.size > before) {
104+
watchLaterChangeCount++;
77105
}
78106
// OR
79-
// myListChangeCount += myList.size - before;
107+
// watchLaterChangeCount += watchLater.size - before;
80108
}
81109

82110
function remove(showID) {
83-
const before = myList.size;
84-
myList.delete(showID);
111+
const before = watchLater.size;
112+
watchLater.delete(showID);
85113

86-
if (before > myList.size) {
87-
myListChangeCount++;
114+
if (before > watchLater.size) {
115+
watchLaterChangeCount++;
88116
}
89117
// OR
90-
//myListChangeCount += before - myList.size;
118+
// watchLaterChangeCount += before - watchLater.size;
91119
}
92120

93-
// myListChangeCount: 0
121+
// watchLaterChangeCount: 0
94122
add(123);
95-
// myListChangeCount: 1
123+
// watchLaterChangeCount: 1
96124
add(123);
97-
// myListChangeCount: 1
125+
// watchLaterChangeCount: 1
98126
remove(123);
99-
// myListChangeCount: 2
127+
// watchLaterChangeCount: 2
100128
remove(123);
101-
// myListChangeCount: 2
129+
// watchLaterChangeCount: 2
102130
```
103131

104132
If you prefer classes, we could write this as:

0 commit comments

Comments
 (0)