Skip to content

Commit 3978782

Browse files
committed
Going wild with promises section
1 parent be4a6dc commit 3978782

File tree

1 file changed

+141
-11
lines changed
  • apps/components_guide_web/lib/components_guide_web/templates/web_standards

1 file changed

+141
-11
lines changed

apps/components_guide_web/lib/components_guide_web/templates/web_standards/promise.html.md

Lines changed: 141 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,18 @@ You can think of a Promise as a value. Once a Promise has been created, you can
44

55
## Promises are eager
66

7-
Let's compare two code samples.
7+
Let's compare two code samples. How many times will we see _Creating value_ logged?
88

99
```js
1010
const promisedValue = new Promise((resolve, reject) => {
11-
console.log("Creating value");
11+
console.log("Creating value"); // Will this be logged once or not at all?
1212
resolve(40 + 2);
1313
});
1414
```
1515

16-
How many times will we see _Creating value_ logged?
17-
1816
```js
1917
const promisedValue = new Promise((resolve, reject) => {
20-
console.log("Creating value");
18+
console.log("Creating value"); // Will this logged three times or once?
2119
resolve(40 + 2);
2220
});
2321

@@ -26,19 +24,17 @@ promisedValue.then(console.log);
2624
promisedValue.then(console.log);
2725
```
2826

29-
Any how many times will we see _Creating value_ logged here?
30-
31-
In both cases, we will see it logged only once, because promises are created eagerly.
27+
In both cases, we will see it logged only once. This is because promises are run once are created eagerly.
3228

33-
Listening to a promise using `.then()` does not affect nor start that promise.
29+
Listening to a promise using `.then()` does not affect nor start that promise. It has no side-effects on the source promise.
3430

3531
Once a promise has been created, then you may wait to hear its result one time, fifteen times, or not at all, and the original promise will behave the same.
3632

3733
This may seem like a strange limitation, but it simplifies reasoning about promises as they work similar to _values_.
3834

3935
### How values work
4036

41-
If we store a value in a variable, we feel comfortable knowing that the reading of that variable has absolutely no effect on its value.
37+
If we store a value in a variable, we can feel comfortable knowing that the reading of that variable has absolutely no effect on its underlying value.
4238

4339
```js
4440
const value = 40 + 2;
@@ -48,8 +44,142 @@ console.log(value);
4844
console.log(value);
4945
```
5046

51-
42 will be logged three times, but if removed the logs altogether, the value will remain the same. The act of logging had no effect on the source value.
47+
The value of `42` will be logged three times, but if the logs were removed altogether, the variable’s value won’t be affected and will remain the same. The act of logging had no effect on the source value.
5248

5349
Promises work exactly the same.
5450

5551
We can use this to our advantage, by thinking about promises in the same way we think about values.
52+
53+
### Reusing
54+
55+
If data is loaded from an API, we might use `fetch()`.
56+
57+
```javascript
58+
const promisedResponse = fetch('https://swapi.dev/api/people/1/');
59+
```
60+
61+
We can chain the response to decode the JSON body of the response.
62+
63+
```javascript
64+
const promisedData = fetch('https://swapi.dev/api/people/1/').then(response => response.json());
65+
```
66+
67+
What happens if we want to use this data again?
68+
69+
```javascript
70+
const promisedData = fetch('https://swapi.dev/api/people/1/')
71+
.then(response => {
72+
console.log('decoding data'); // How many times will we see this logged?
73+
return response.json();
74+
});
75+
76+
promisedData.then(data => {
77+
// Use data
78+
});
79+
80+
promisedData.then(data => {
81+
// Use data again
82+
});
83+
```
84+
85+
Here will see `decoding data` logged once. The `fetch()` call returns a Promise, which is chained using `.then()` to unwrap the underlying JSON body by calling `.json()` on the response.
86+
87+
We can continue to think of these as eventual values. Once these values have been cast, they cannot change (technically we could mutate anything as JavaScript gives us free reign but we shouldn’t).
88+
89+
The response from `fetch()` is one eventual value. The decode JSON is another eventual value, and actually has two Promises, one created by the `.json()` method, and another wrapping that created by `.then()`.
90+
91+
```javascript
92+
const promisedResponse = fetch('https://swapi.dev/api/people/1/');
93+
const promisedData = promisedResponse.then(response => {
94+
const promisedDataInner = response.json();
95+
return promisedDataInner;
96+
});
97+
```
98+
99+
If it seems confusing that there’s actually two Promises for the one JSON value, consider if we delayed
100+
101+
```javascript
102+
function callIn(timeout) {
103+
return {
104+
then: (callback) => setTimeout(callback, timeout)
105+
};
106+
}
107+
108+
Promise.resolve(callIn(500));
109+
110+
const promisedResponse = fetch('https://swapi.dev/api/people/1/');
111+
const promisedData = promisedResponse.then(response => {
112+
return {
113+
then: (callback, reject) => {
114+
console.log('reject', reject);
115+
setTimeout(() => {
116+
callback(response.json());
117+
}, 1000);
118+
}
119+
}
120+
});
121+
```
122+
123+
### Async Await
124+
125+
The same applies if the code is rewritten to use `async await`. The underlying objects are still Promises.
126+
127+
### Failure
128+
129+
```javascript
130+
const fallbackData = {
131+
name: "Jane Doe",
132+
height: "168",
133+
mass: "67",
134+
};
135+
136+
fetch('https://swapi.dev/api/people/1/')
137+
.then(res => res.data())
138+
.catch(() => fallbackData);
139+
```
140+
141+
### Caching
142+
143+
```javascript
144+
function sideEffect(send, transform) {
145+
return (value) => ({
146+
then(resolve) {
147+
const transformed = transform(value);
148+
resolve(transformed);
149+
send(transformed);
150+
}
151+
})
152+
}
153+
154+
function cacheStorer(cache, key, transform) {
155+
return sideEffect(value => cache.set(key, transform(value)));
156+
}
157+
158+
function localStorageStorer(key) {
159+
return sideEffect(value => window.localStorage.setItem(key, value));
160+
}
161+
162+
const cachedValues = new WeakMap();
163+
function useCacheKey(cache, key) {
164+
return [cache.get.bind(cache, key), cache.set(cache, key)];
165+
}
166+
167+
function fetchCached(url) {
168+
const [read, write] = useCacheKey(cachedValues, url);
169+
170+
const promise = read(url);
171+
if (promise) {
172+
return promise;
173+
} else {
174+
return fetch(url).then(
175+
sideEffect(write, Promise.resolve),
176+
sideEffect(write, Promise.reject)
177+
);
178+
}
179+
}
180+
function fetchCached(url) {
181+
return Promise.resolve(cachedValues.get(url) || fetch(url).then(cacheStorer(cachedValues, url)));
182+
}
183+
```
184+
185+
### Chaining

0 commit comments

Comments
 (0)