11
22# Promise 链
33
4- 我们回顾一下 < info:callbacks > 一章中提到的问题:我们有一系列的异步任务要一个接一个地执行 — 例如,加载脚本。我们如何写出更好的代码呢?
4+ 我们回顾一下 < info:callbacks > 一章中提到的问题:我们有一系列的异步任务要一个接一个地执行 —— 例如,加载脚本。我们如何写出更好的代码呢?
55
66Promise 提供了一些方案来做到这一点。
77
@@ -36,17 +36,17 @@ new Promise(function(resolve, reject) {
3636
3737运行流程如下:
38381 . 初始 promise 在 1 秒后 resolve ` (*) ` ,
39- 2 . 然后 ` .then ` 处理程序(handler)被调用 ` (**) ` ,它又创建了一个新的 promise(以 ` 2 ` 作为值 resolve)。
40- 3 . 下一个 ` then ` ` (***) ` 得到了前一个 ` then ` 的值,对该值进行处理(* 2)并将其传递给下一个处理程序(handler) 。
39+ 2 . 然后 ` .then ` 处理程序被调用 ` (**) ` ,它又创建了一个新的 promise(以 ` 2 ` 作为值 resolve)。
40+ 3 . 下一个 ` then ` ` (***) ` 得到了前一个 ` then ` 的值,对该值进行处理(* 2)并将其传递给下一个处理程序。
41414 . ……依此类推。
4242
43- 随着 result 在处理程序(handler)链中传递 ,我们可以看到一系列的 ` alert ` 调用:` 1 ` -> ` 2 ` -> ` 4 ` 。
43+ 随着 result 在处理程序链中传递 ,我们可以看到一系列的 ` alert ` 调用:` 1 ` -> ` 2 ` -> ` 4 ` 。
4444
4545![ ] ( promise-then-chain.svg )
4646
4747这样之所以是可行的,是因为每个对 ` .then ` 的调用都会返回了一个新的 promise,因此我们可以在其之上调用下一个 ` .then ` 。
4848
49- 当处理程序(handler)返回一个值时 ,它将成为该 promise 的 result,所以将使用它调用下一个 ` .then ` 。
49+ 当处理程序返回一个值时 ,它将成为该 promise 的 result,所以将使用它调用下一个 ` .then ` 。
5050
5151** 新手常犯的一个经典错误:从技术上讲,我们也可以将多个 ` .then ` 添加到一个 promise 上。但这并不是 promise 链(chaining)。**
5252
@@ -72,21 +72,21 @@ promise.then(function(result) {
7272});
7373```
7474
75- 我们在这里所做的只是一个 promise 的几个处理程序(handler) 。它们不会相互传递 result;相反,它们之间彼此独立运行处理任务。
75+ 我们在这里所做的只是一个 promise 的几个处理程序。它们不会相互传递 result;相反,它们之间彼此独立运行处理任务。
7676
77- 这里它的一张示意图 (你可以将其与上面的链式调用做一下比较):
77+ 这是它的一张示意图 (你可以将其与上面的链式调用做一下比较):
7878
7979![ ] ( promise-then-many.svg )
8080
81- 在同一个 promise 上的所有 ` .then ` 获得的结果都相同 — 该 promise 的结果。所以,在上面的代码中,所有 ` alert ` 都显示相同的内容:` 1 ` 。
81+ 在同一个 promise 上的所有 ` .then ` 获得的结果都相同 —— 该 promise 的结果。所以,在上面的代码中,所有 ` alert ` 都显示相同的内容:` 1 ` 。
8282
83- 实际上我们极少遇到一个 promise 需要多处理程序(handler)的情况 。使用链式调用的频率更高。
83+ 实际上我们极少遇到一个 promise 需要多个处理程序的情况 。使用链式调用的频率更高。
8484
8585## 返回 promise
8686
8787` .then(handler) ` 中所使用的处理程序(handler)可以创建并返回一个 promise。
8888
89- 在这种情况下,其他的处理程序(handler)将等待它 settled 后再获得其结果(result) 。
89+ 在这种情况下,其他的处理程序将等待它 settled 后再获得其结果。
9090
9191例如:
9292
@@ -120,7 +120,7 @@ new Promise(function(resolve, reject) {
120120});
121121```
122122
123- 这里第一个 ` .then ` 显示 ` 1 ` 并在 ` (*) ` 行返回 ` new Promise(…) ` 。1 秒后它会进行 resolve,然后 result(` resolve ` 的参数,在这里它是 ` result*2 ` )被传递给第二个 ` .then ` 的处理程序(handler)。这个处理程序(handler)位于 ` (**) ` 行,它显示 ` 2 ` ,并执行相同的动作(action) 。
123+ 这里第一个 ` .then ` 显示 ` 1 ` 并在 ` (*) ` 行返回 ` new Promise(…) ` 。1 秒后它会进行 resolve,然后 result(` resolve ` 的参数,在这里它是 ` result*2 ` )被传递给第二个 ` .then ` 的处理程序。这个处理程序位于 ` (**) ` 行,它显示 ` 2 ` ,并执行相同的行为 。
124124
125125所以输出与前面的示例相同:1 -> 2 -> 4,但是现在在每次 ` alert ` 调用之间会有 1 秒钟的延迟。
126126
@@ -164,7 +164,7 @@ loadScript("/article/promise-chaining/one.js")
164164
165165在这儿,每个 ` loadScript ` 调用都返回一个 promise,并且在它 resolve 时下一个 ` .then ` 开始运行。然后,它启动下一个脚本的加载。所以,脚本是一个接一个地加载的。
166166
167- 我们可以向链中添加更多的异步行为(action) 。请注意,代码仍然是“扁平”的 — 它向下增长,而不是向右。这里没有“厄运金字塔”的迹象。
167+ 我们可以向链中添加更多的异步行为。请注意,代码仍然是“扁平”的 — — 它向下增长,而不是向右。这里没有“厄运金字塔”的迹象。
168168
169169从技术上讲,我们可以向每个 ` loadScript ` 直接添加 ` .then ` ,就像这样:
170170
@@ -189,7 +189,7 @@ loadScript("/article/promise-chaining/one.js").then(script1 => {
189189
190190
191191```` smart header="Thenables"
192- 确切地说,处理程序(handler)返回的不完全是一个 promise,而是返回的被称为 "thenable" 对象 — 一个具有方法 `.then` 的任意对象。它会被当做一个 promise 来对待。
192+ 确切地说,处理程序返回的不完全是一个 promise,而是返回的被称为 "thenable" 对象 — — 一个具有方法 `.then` 的任意对象。它会被当做一个 promise 来对待。
193193
194194这个想法是,第三方库可以实现自己的“promise 兼容(promise-compatible)”对象。它们可以具有扩展的方法集,但也与原生的 promise 兼容,因为它们实现了 `.then` 方法。
195195
@@ -216,7 +216,7 @@ new Promise(resolve => resolve(1))
216216 .then(alert); // 1000ms 后显示 2
217217```
218218
219- JavaScript 检查在 `(*)` 行中由 `.then` 处理程序(handler)返回的对象 :如果它具有名为 `then` 的可调用方法,那么它将调用该方法并提供原生的函数 `resolve` 和 `reject` 作为参数(类似于 executor),并等待直到其中一个函数被调用。在上面的示例中,`resolve(2)` 在 1 秒后被调用 `(**)`。然后,result 会被进一步沿着链向下传递。
219+ JavaScript 检查在 `(*)` 行中由 `.then` 处理程序返回的对象 :如果它具有名为 `then` 的可调用方法,那么它将调用该方法并提供原生的函数 `resolve` 和 `reject` 作为参数(类似于 executor),并等待直到其中一个函数被调用。在上面的示例中,`resolve(2)` 在 1 秒后被调用 `(**)`。然后,result 会被进一步沿着链向下传递。
220220
221221这个特性允许我们将自定义的对象与 promise 链集成在一起,而不必继承自 `Promise`。
222222````
@@ -226,15 +226,15 @@ JavaScript 检查在 `(*)` 行中由 `.then` 处理程序(handler)返回的
226226
227227在前端编程中,promise 通常被用于网络请求。那么,让我们一起来看一个相关的扩展示例吧。
228228
229- 我们将使用 [ fetch] ( info:fetch ) 方法从远程服务器加载用户信息。它有很多可选的参数,我们在 [ 单独的一章] ( info:fetch ) 中对其进行了详细介绍,但是基本语法很简单 :
229+ 我们将使用 [ fetch] ( info:fetch ) 方法从远程服务器加载用户信息。它有很多可选的参数,我们在 [ 单独的一章] ( info:fetch ) 中对其进行了详细介绍,但基本语法很简单 :
230230
231231``` js
232232let promise = fetch (url);
233233```
234234
235235执行这条语句,向 ` url ` 发出网络请求并返回一个 promise。当远程服务器返回 header(是在 ** 全部响应加载完成前** )时,该 promise 使用一个 ` response ` 对象来进行 resolve。
236236
237- 为了读取完整的响应,我们应该调用 ` response.text() ` 方法:当全部文字(full text)内容从远程服务器下载完成后 ,它会返回一个 promise,该 promise 以刚刚下载完成的这个文本作为 result 进行 resolve。
237+ 为了读取完整的响应,我们应该调用 ` response.text() ` 方法:当全部文字内容从远程服务器下载完成后 ,它会返回一个 promise,该 promise 以刚刚下载完成的这个文本作为 result 进行 resolve。
238238
239239下面这段代码向 ` user.json ` 发送请求,并从服务器加载该文本:
240240
@@ -247,20 +247,20 @@ fetch('/article/promise-chaining/user.json')
247247 return response .text ();
248248 })
249249 .then (function (text ) {
250- // ... 这是远程文件的内容
250+ // …… 这是远程文件的内容
251251 alert (text); // {"name": "iliakan", "isAdmin": true}
252252 });
253253```
254254
255- 从 ` fetch ` 返回的 ` response ` 对象还包括 ` response.json() ` 方法,该方法读取远程数据并将其解析为 JSON。在我们的例子中,这更加方便,所以让我们切换到这个方法 。
255+ 从 ` fetch ` 返回的 ` response ` 对象还包含 ` response.json() ` 方法,该方法可以读取远程数据并将其解析为 JSON。在我们的例子中,这更加方便,所以我们用这个方法把 。
256256
257257为了简洁,我们还将使用箭头函数:
258258
259259``` js run
260- // 同上,但是使用 response.json() 将远程内容解析为 JSON
260+ // 同上,但使用 response.json() 将远程内容解析为 JSON
261261fetch (' /article/promise-chaining/user.json' )
262262 .then (response => response .json ())
263- .then (user => alert (user .name )); // iliakan, got user name
263+ .then (user => alert (user .name )); // iliakan,获取到了用户名
264264```
265265
266266现在,让我们用加载好的用户信息搞点事情。
@@ -287,7 +287,7 @@ fetch('/article/promise-chaining/user.json')
287287 });
288288```
289289
290- 这段代码可以工作,具体细节请看注释。但是,这儿有一个潜在的问题 ,一个新手使用 promise 的典型问题 。
290+ 这段代码可以工作,具体细节请看注释。但是,这有一个潜在的问题 ,一个新手使用 promise 时的典型问题 。
291291
292292请看 ` (*) ` 行:我们如何能在头像显示结束并被移除 ** 之后** 做点什么?例如,我们想显示一个用于编辑该用户或者其他内容的表单。就目前而言,是做不到的。
293293
@@ -319,7 +319,7 @@ fetch('/article/promise-chaining/user.json')
319319 .then (githubUser => alert (` Finished showing ${ githubUser .name } ` ));
320320```
321321
322- 也就是说,第 ` (*) ` 行的 ` .then ` 处理程序(handler)现在返回一个 ` new Promise ` ,只有在 ` setTimeout ` 中的 ` resolve(githubUser) ` ` (**) ` 被调用后才会变为 settled。链中的下一个 ` .then ` 将一直等待这一时刻的到来。
322+ 也就是说,第 ` (*) ` 行的 ` .then ` 处理程序现在返回一个 ` new Promise ` ,只有在 ` setTimeout ` 中的 ` resolve(githubUser) ` ` (**) ` 被调用后才会变为 settled。链中的下一个 ` .then ` 将一直等待这一时刻的到来。
323323
324324作为一个好的做法,异步行为应该始终返回一个 promise。这样就可以使得之后我们计划后续的行为成为可能。即使我们现在不打算对链进行扩展,但我们之后可能会需要。
325325
@@ -359,7 +359,7 @@ loadJson('/article/promise-chaining/user.json')
359359
360360## 总结
361361
362- 如果 ` .then ` (或 ` catch/finally ` 都可以)处理程序(handler)返回一个 promise,那么链的其余部分将会等待,直到它状态变为 settled。当它被 settled 后,其 result(或 error)将被进一步传递下去。
362+ 如果 ` .then ` (或 ` catch/finally ` 都可以)处理程序返回一个 promise,那么链的其余部分将会等待,直到它状态变为 settled。当它被 settled 后,其 result(或 error)将被进一步传递下去。
363363
364364这是一个完整的流程图:
365365
0 commit comments