-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path4-5.html
179 lines (178 loc) · 6.66 KB
/
4-5.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
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="./public/favicon.ico" />
<meta http-equiv="cache-control" content="no-cache" />
<title></title>
<link rel="stylesheet" href=" https://necolas.github.io/normalize.css/8.0.1/normalize.css" />
<link rel="stylesheet" href="./hightlight/default.min.css" />
<link rel="stylesheet" href="./css/main.css" />
<link rel="stylesheet" href="./css/copybutton.css" />
<link rel="stylesheet" href="./css/hightlight.css" />
<script src="./hightlight/hightlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.11/clipboard.min.js"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-BEVZJDBC7Z"></script>
<script src="./js/gtag.js"></script>
</head>
<body>
<header>
<nav>
<h1>
<span id="toggle-menu"></span>
<a href="index.html"></a>
</h1>
</nav>
</header>
<main>
<aside>
<nav></nav>
</aside>
<article>
<h2>4-5 非同步迭代</h2>
<p>
如第109 頁第4.2節,「迭代器協議 (Iterator Protocol)和可迭代協議(Iterable
Protocol)」所說明,你應該還記得迭代器如何運用 Symbol.iterator
作為一個介面,定義物件被迭代的方式。
</p>
<pre><code class="language-js">
const sequence = {
[Symbol.iterator](){
const items = ['i', 't','e', 'r','a','b', 'l', 'e']
return {
next: ()=> ({
done: items.length === 0,
value: items.shift()
})
}
}
}
</code></pre>
<p>
你可能記得 sequence 物件可用多種不同的方式進行迭代,例如:展開運算子、Array.from、for..of
和其他方式。
</p>
<pre><code class="language-js">
[...sequence]
// ['i', 't','e', 'r','a','b', 'l', 'e']
Array.from(sequence)
// ['i', 't','e', 'r','a','b', 'l', 'e']
for (const item of sequence) {
console.log(item)
// 'i'
// 't'
// 'e'
// 'r'
// 'a'
// 'b'
// 'l'
// 'e'
}
</code></pre>
<p>
迭代器定義中規定,Symbol.iterator 的 next 方法必須回傳一個具有 value 和 done
特性的物件;valve 特性代表的是目前在序列中的資料值,而 done
特性是一個布林值,標示著目前序列是否結束。
</p>
<h3 id="4-5-1">4-5-1 非同步迭代器</h3>
<p>
在非同步迭代器中,定義上稍有不同:next 方法預期會回傳一個 Promise 物件,它可解析出包含
value 和 done 特性的物件。這個 Promise
物件可以啟用一個序列來定義非同步的工作,在資料項被解析而得之前。為了避免與 Symbol.iterator
所產生的結果混淆,此處介紹一個新的 Symbol.asyncIterator ,用以宣告非同步迭代器。
</p>
<p>
可迭代物件 sequence 只要進行兩項小調整,就可以與非同步迭代器介面相容運作:將
Symbol.iterator 以 Symbol.asyncIterator 取代,並且將 Promise.resolve 中的 next
方法的回傳值,改為回傳一個 Promise 物件。
</p>
<pre><code class="language-js">
const sequence = {
[Symbol.asyncIterator](){
const items = ['i', 't' , 'e', 'r' , 'a' , 'b', 'l', 'e']
return {
next: ()=> Promise.resolve({
done: items.length === 0,
value: items.shift()
})
}
}
}
</code></pre>
<p>
下面是一個無限量序列在指定的時間區間中增加其值的範例。在程式碼中,interval
函式會回傳無限量非同步序列。在指定的 duration 時間後,每個步驟會解析出序列中的下一個值。
</p>
<pre><code class="language-js">
const interval = duration => ({
[Symbol.asyncIterator]:()=> ({
i: 0,
next(){
return new Promise(resolve=>
setTimeout(() => resolve({
value: this.i++,
done: false
}), duration)
)
}
})
})
</code></pre>
<p>
為了使用非同站迭代器,我們可以選用新的 for await..of
流程元件搭配非同步迭代器一同使用。這也是另一種以看似同步的流程撰寫非同步程式碼的方式。請注意,for
await..of 敘述只允許於非同步函式中使用。
</p>
<pre><code class="language-js">
async function print (){
for await (const i of interval(1000)) {
console.log(`${ i } seconds elapsed.` )
}
}
print()
</code></pre>
<h3 id="4-5-2">4-5-2 非同步產生器</h3>
<p>
就像一般的迭代器,非同步產生器可與非同步迭代器在功能上有互補的作用。非同步產生器函式也就像是一個產生器函式,除了它還可以支援
await 和for await..of 的宣告方式。下面的範例示範一個名稱為 fetchInterval
的產生器可定期地於固定的時間區間進行資源擷取。
</p>
<pre><code class="language-js">
async function* fetchInterval (duration,...params) {
for await (const i of interval (duration)){
yield await fetch(... params)
}
}
</code></pre>
<p>
當逐步進行時,非同步產生器會回傳具有 {next, return, throw} 特徵的物件,物件的方法可回傳
Promise 物件並具備{ value, done } 特性。相較於一般的產生器,它們是直接的回傳 { value,
done } 子結果。
</p>
<p>
使用 fetchInterval 非同步產生器的方式,則與你使用以物件為基礎的 interval
非同步迭代器完全相同。以下的範例會使用 fetchInterval 產生器來擷取一個 /api/status 的 HTTP
資源,並且使用它的 JSON
回傳結果。在每次的步驟結束後,程式會等待一秒鐘,下次再重複進行相同的步驟。
</p>
<pre><code class="language-js">
async function process() {
for await (const response of fetchInterval(1000, '/api/status' )) {
const data = await response.json()
// 使用最新的資料
}
}
process()
</code></pre>
<p>
如第112 頁第4.2.2
節「無限量序列」所強調的重點,中斷這類序列的方法是很重要的,以避免程式產生無限迥圈。
</p>
</article>
</main>
</body>
<script type="module" src="./js/main.js"></script>
</html>