0%

Introduction to Javascript Asynchronous Programming

我只是個Javascript初新者,寫出來的可能也會務人子弟。
只是對Javascript的Asynchronous Programming Model有興趣,紀錄一下。

Callback Hell

在最初的Javascript的設計,程式只能這樣寫。一層又一層的Callback。不蛋難以維護,並且容易出錯。

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
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function asyncTask() {
var val = 0;
wait((val) => {
console.log("Step 1");
console.log(val);
wait((val) => {
console.log("Step 2");
console.log(val);
wait((val) => {
console.log("Step 3");
console.log(val);
wait((val) => {
console.log("Finish");
console.log(val);
}, val + 4);
}, val + 3);
}, val + 2);
}, val + 1);
}

asyncTask();

ES6之後引季Promise,可以將Callback從水平拓展變成垂直拓展,讓程式碼更像是一般Synchronous Programming的方式

Promise

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
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function finish(val) {
console.log("Finish");
console.log(val);
}
function step3(val) {
console.log("Step 3");
console.log(val);
}
function step2(val) {
console.log("Step 2");
console.log(val);
}
function step1(val) {
console.log("Step 1");
console.log(val);
}
function waitPromise(func, val) {
return new Promise((resolve, reject) => {
wait(() => {
func(val);
resolve(val);
});
});
}
function asyncTask() {
var val = 0;
return waitPromise(step1, val + 1).then((val) => {
return waitPromise(step2, val + 2);
}).then((val) => {
return waitPromise(step3, val + 3);
}).then((val) => {
return waitPromise(finish, val + 4);
});
}

asyncTask();


asyncTask();

Generator

不過ES6同樣引入了Generator,可以用Generator模擬Synchronous Programming的方式
asyncTaskFlow是個Generator就是控制流,只是我們要以這個順序執行
比起Promise更像是我們熟悉的方式

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
function wait(func) {
return setTimeout(func, 1000);
}
function finish() {
console.log("Finish");
}
function step3() {
console.log("Step 3");
}
function step2() {
console.log("Step 2");
}
function step1() {
console.log("Step 1");
}
function* asyncTaskFlow() {
yield wait(step1);
yield wait(step2);
yield wait(step3);
yield wait(finish);
}
function asyncTask() {
var gen = asyncTaskFlow();
for (v of gen) ;
}

asyncTask();

Async & Await

跟C#一樣,用Async和Awit作為最終解決方案,雖然這還處在ES7 Draft,不過日後應該會被採用
可以參考 ES7 async functionsSimplifying Asynchronous Coding with ES7 Async Functions

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
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3");
resolve(val + 3);
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
}
asyncTask();
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
function wait(func) {
return setTimeout(func, 1000);
}
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3 failed");
reject("Cancel operation");
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
try {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
} catch (err) {
console.log(err);
}
}
asyncTask();