-
Notifications
You must be signed in to change notification settings - Fork 0
/
7.2_Promise_Async,await.html
194 lines (162 loc) · 7.3 KB
/
7.2_Promise_Async,await.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
<!DOCTYPE html>
<html>
<head>
<script>
// Promise: The constructor syntax for a promise object is:
let promise = new Promise(function(resolve, reject) {
// executor (the producing code, "singer")
});
/*The function passed to new Promise is called the executor. When new Promise is created, the executor runs automatically. It contains the producing code which should eventually produce the result. In terms of the analogy above: the executor is the “singer”.
Its arguments resolve and reject are callbacks provided by JavaScript itself. Our code is only inside the executor.
When the executor obtains the result, be it soon or late, doesn’t matter, it should call one of these callbacks:
resolve(value) — if the job is finished successfully, with result value.
reject(error) — if an error has occurred, error is the error object.
So to summarize: the executor runs automatically and attempts to perform a job. When it is finished with the attempt, it calls resolve if it was successful or reject if there was an error.
The promise object returned by the new Promise constructor has these internal properties:
state — initially "pending", then changes to either "fulfilled" when resolve is called or "rejected" when reject is called.
result — initially undefined, then changes to value when resolve(value) is called or error when reject(error) is called.
So the executor eventually moves promise to one of these states:
new Promise(extractor): state: 'pending', result: undefined
? resolve(value) => state: 'fufilled', result: value
: state: 'rejected', result: error
Later we’ll see how “fans” can subscribe to these changes.
Here’s an example of a promise constructor and a simple executor function with “producing code” that takes time (via setTimeout):
*/
promise = new Promise(function(resolve, reject) {
//the function is executed autuomatically when promise is contruucted
// after 1 second signal that job is done with result 'done'
//setTimeout( () => resolve('done'), 1000);
setTimeout( () => reject( new Error('Oops')), 500); }
);
// promise.then(
// result => console.log(result), //shows done
// error => console.log(error) //shows oops
// );
promise.catch(console.log);
//Catch is used for error handling
/* Task 2
Delay with a promise
The built-in function setTimeout uses callbacks. Create a promise-based alternative.
The function delay(ms) should return a promise. That promise should resolve after ms milliseconds, so that we can add .then to it, like this:
*/
function delay(ms) {
promise = new Promise( function (resolve, reject)
{
setTimeout( () => resolve('done'), ms);
});
return promise;
}
delay(3000).then(() => console.log('runs after 3 seconds'));
/* Promise chaining: just like chaining functions, promise can be chained, i.e., The idea is that the result is passed through the chain of .then handlers. Let's see an example to return promises:
*/
new Promise( function ( resolve, reject) {
setTimeout ( () => resolve(1), 1000);
}).then(function (result) {
console.log(result); //1
return new Promise((resolve, reject) => { //(*)
setTimeout(() => resolve(result*2), 1000);
});
}).then(function(result) { // (**)
console.log(result); //2
return new Promise(( resolve, reject) => {
setTimeout(() => resolve(result*2), 1000);
});
}).then(function(result){
console.log(result); //4
});
//Rethrowing: If we throw inside .catch, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the next closest successful .then handler.
new Promise((resolve, reject) => {
throw new Error ("Whoops!");
}).catch(function(error) {
if(error instanceof URIError) {
// handle it
}
else { console.log("Can't handle such error");
throw error;
}
}).then(function() {
//doesn't run here
}).catch( error => {
console.log('The unknown error has occured:'+error);
})
//Unhandled rejection: If there is no catch then the script gives error in console log.
new Promise(function() {
// noSuchFunction(); // Error here (no such function)
})
.then(() => {
// successful promise handlers, one or more
}); // without .catch at the end!
new Promise(function(resolve, reject) {
throw new Error("Whoops!");
}).catch(console.log);
/* Task 3
Rewrite using async/await
Rewrite this example code from the chapter Promises chaining using async/await instead of .then/catch:
*/
async function loadJson(url) {
let response = await fetch(url);
if (response.status == 200) {
let json = response.json();
return json;
} else {
throw new Error(response.status);
}
}
loadJson('https://javascript.info/no-such-user.json')
.catch(alert); // Error: 404
/* Task 4
Rewrite "rethrow" with async/await
Below you can find the “rethrow” example. Rewrite it using async/await instead of .then/catch.
And get rid of the recursion in favour of a loop in demoGithubUser: with async/await that becomes easy to do.
*/
class HttpError extends Error {
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
async function loadJson(url) {
let response = await fetch(url);
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
}
// Ask for a user name until github returns a valid user
async function demoGithubUser() {
let user;
while(true) {
let name = prompt("Enter a name?", "iliakan");
try {
user = await loadJson(`https://api.github.com/users/${name}`);
break; //no error
} catch(err) {
if (err instanceof HttpError && err.response.status == 404) {
console.log("No such user, please reenter.");
} else {
throw err;
}
}
}
console.log("Full name: "+user.name);
return user;
}
demoGithubUser();
/* Task 5
Call async from non-async
We have a “regular” function called f. How can you call the async function wait() and use its result inside of f?
*/
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
return 10;
}
function f() {
wait().then(result => console.log(result));
}
f();
//P.S. The task is technically very simple, but the question is quite common for developers new to async/await.
</script>
</head>
</html>