Skip to content

Commit 3f49c43

Browse files
committed
Promise 快完成了
1 parent b5b322c commit 3f49c43

File tree

7 files changed

+259
-3
lines changed

7 files changed

+259
-3
lines changed

02-04-promise-advanced.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Promise 进阶
2+
========

02-1-promise-basic.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,29 @@ Promise.resolve()
129129

130130
### 继续 `.then()` 的话题
131131

132-
结合上一小节关于 Promise.resolve() 的讲解,我们应该可以推断出 `.then()` 里的状态响应函数不同返回结果对进程的影响了吧。
132+
结合上一小节关于 Promise.resolve() 的讲解,我们应该可以推断出 `.then()` 里的状态响应函数返回不同结果对进程的影响了吧。
133+
134+
好的,那我们换一个思路,假如一个 Promise 已经完成了,再给它加一个 `.then()`,会是什么效果呢?我们来试一下。
135+
136+
```javascript
137+
let promise = new Promise(resolve => {
138+
setTimeout(() => {
139+
console.log('the promise fulfilled');
140+
resolve('hello, world');
141+
}, 1000);
142+
});
143+
144+
setTimeout(() => {
145+
promise.then( value => {
146+
console.log(value);
147+
});
148+
}, 3000);
149+
150+
// 输出
151+
// (1秒后)the promise fulfilled
152+
// (3秒后)hello, world
153+
```
154+
155+
1秒后,Promise 完成;3秒后,给它续上一个 `.then()`,因为它已经处于 `fulfilled` 状态,所以立刻执行响应函数,输出“hello, world”。
156+
157+
这一点很值得我们关注。Promise 从队列操作中脱胎而成,带有很强的队列属性。异步回调开始执行后,我们无法追加操作,也无法判定结束时间。而使用 Promise 的话,我们就可以不关心它什么时候开始什么时候结束,只需要在队列后面追加操作即可。

02-2-promise-advanced.md

Whitespace-only changes.

02-2-promise-test.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
Promise 小测验
2+
========
3+
4+
好的,我们已经初步了解了 Promise 的使用方式,了解了 `.then()` 怎么处理响应函数,返回新的 Promise 实例。接下来我们看一个小测验,看看大家的掌握程度。
5+
6+
> 下面这道题出自 [We have a problem with promises](https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html)
7+
8+
**问题:下面的四种 promises 的区别是什么?**
9+
10+
我们假定 `doSomething()``doSomethingElse()` 都会返回 Promise 对象。
11+
12+
```javascript
13+
// #1
14+
doSomething().then(function () {
15+
return doSomethingElse();
16+
});
17+
18+
// #2
19+
doSomething().then(function () {
20+
doSomethingElse();
21+
});
22+
23+
// #3
24+
doSomething().then(doSomethingElse());
25+
26+
// #4
27+
doSomething().then(doSomethingElse);
28+
```
29+
30+
仔细看一看,默想一下答案,不要着急往下翻。
31+
32+
好,准备好了么?我们继续了哟。
33+
34+
3...
35+
36+
2..
37+
38+
1.
39+
40+
## 答案揭晓
41+
42+
### 第一题
43+
44+
```javascript
45+
doSomething()
46+
.then(function () {
47+
return doSomethingElse();
48+
})
49+
.then(finalHandler);
50+
```
51+
52+
答案:
53+
54+
```
55+
doSomething
56+
|-----------|
57+
doSomethingElse(undefined)
58+
|------------|
59+
finalHandler(resultOfDoSomethingElse)
60+
|------------|
61+
```
62+
63+
这道题比较简单,几乎和前面的例子一样,我就不多说了。
64+
65+
### 第二题
66+
67+
```javascript
68+
doSomething()
69+
.then(function () {
70+
doSomethingElse();
71+
})
72+
.then(finalHandler);
73+
```
74+
75+
答案:
76+
77+
```
78+
doSomething
79+
|-----------------|
80+
doSomethingElse(undefined)
81+
|------------------|
82+
finalHandler(undefined)
83+
|------------------|
84+
```
85+
86+
这道题就有一定难度了。虽然 `doSomethingElse` 会返回 Promise 对象,但是因为 `.then()` 的响应函数并没有把它 `return` 出来,所以这里其实相当于 `return null`。我们知道,`Promise.resolve()` 在参数为空的时候会返回一个状态为 `fulfilled` 的 Promise,所以这里两步是一起执行的。
87+
88+
### 第三题
89+
90+
```javascript
91+
doSomething()
92+
.then(doSomethingElse())
93+
.then(finalHandler);
94+
```
95+
96+
答案:
97+
98+
```
99+
doSomething
100+
|-----------------|
101+
doSomethingElse(undefined)
102+
|---------------------------------|
103+
finalHandler(resultOfDoSomething)
104+
|------------------|
105+
```
106+
107+
这一题的语法陷阱也不小。首先,`doSomethingElse``doSomethingElse()` 的区别在于,前者是一个变量,引用一个函数;而后者是则是直接执行了函数,并返回其返回值。所以这里 `doSomethingElse` 立刻就开始执行了,和前面 `doSomething` 的启动时间相差无几,可以忽略不计。然后,按照 Promise 的设计,当 `.then()` 的参数不是函数的时候,这一步会被忽略不计,所以 `doSomething` 完成后就跳去执行 `finalHandler` 了。
108+
109+
### 第四题
110+
111+
```javascript
112+
doSomething()
113+
.then(doSomethingElse)
114+
.then(finalHandler);
115+
```
116+
117+
答案:
118+
119+
```
120+
doSomething
121+
|-----------|
122+
doSomethingElse(resultOfDoSomething)
123+
|------------|
124+
finalHandler(resultOfDoSomethingElse)
125+
|------------------|
126+
```
127+
128+
这一题比较简单,就不解释了。
129+
130+
--------
131+
132+
怎么样?都答对了么?还是有点小难度的,对吧?

02-3-promise-error.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
Promise 进阶
2+
========
3+
4+
我们继续学习 Promise。
5+
6+
## 错误处理
7+
8+
Promise 会自动捕获内部异常,并交给 `rejected` 响应函数处理。比如下面这段代码:
9+
10+
```javascript
11+
new Promise( resolve => {
12+
setTimeout( () => {
13+
throw new Error('bye');
14+
}, 2000);
15+
})
16+
.then( value => {
17+
console.log( value + ' world');
18+
})
19+
.catch( error => {
20+
console.log( 'Error: ', error.message);
21+
22+
// 输出:
23+
// (2秒后)Error: bye
24+
// at Timeout.setTimeout [as _onTimeout] (/path/to/error.js:7:11)
25+
// at ontimeout (timers.js:488:11)
26+
// at tryOnTimeout (timers.js:323:5)
27+
// at Timer.listOnTimeout (timers.js:283:5)
28+
```
29+
30+
可以看到,2秒之后,因为在 Promise 的执行器里抛出了错误,所以跳过了 `.then()`,进入 `.catch()` 处理异常。
31+
32+
正如我们前面所说,`.then(fulfilled, reject)` 其实接收两个参数,分别作为成功与失败的回调。不过在实践中,我更推荐上面的做法,即不传入第二个参数,而是把它放在后面的 `.catch()` 里面。这样有两个好处:
33+
34+
1. 更加清晰,更加好读
35+
2. 可以捕获前面所有 `.then()` 的错误,而不仅是这一步的错误
36+
37+
> 在小程序里需要注意,抛出的错误会被全局捕获,而 `.catch` 反而不执行,所以该用两个参数还是要用。
38+
39+
## 更复杂的情况
40+
41+
当队列很长的时候,情况又如何呢?我们看一段代码:
42+
43+
```javascript
44+
new Promise(resolve => {
45+
setTimeout(() => {
46+
resolve();
47+
}, 1000);
48+
})
49+
.then( () => {
50+
console.log('start');
51+
throw new Error('test error');
52+
})
53+
.catch( err => {
54+
console.log('I catch: ', err);
55+
56+
// 下面这一行的注释将引发不同的走向
57+
// throw new Error('another error');
58+
})
59+
.then( () => {
60+
console.log('arrive here');
61+
})
62+
.then( () => {
63+
console.log('... and here');
64+
})
65+
.catch( err => {
66+
console.log('No, I catch: ', err);
67+
});
68+
69+
// 输出:
70+
// start
71+
// I catch: test err
72+
// arrive here
73+
// ... and here
74+
```
75+
76+
实际上,`.catch()` 仍然会使用 `Promise.resolve()` 返回其中的响应函数的执行结果,与 `.then()` 并无不同。所以 `.catch()` 之后的 `.then()` 仍然会执行,如果想彻底跳出执行,就必须继续抛出错误,比如把上面代码中的 `another error` 那行注释掉。这也需要大家注意。
77+
78+
## 总结
79+
80+
简单总结一下 Promise 的错误处理。与异步回调相比,它的作用略强,可以抛出和捕获,基本可以按照预期的状态执行。然而它仍然不是真正的 `try/catch/throw`,在队列很长的时候,捕获错误也很容易出错,所以还要小心。
81+
82+
另外,所有执行器和响应函数里的错误都不会真正进入全局环境,所以我们有必要在所有队列的最后一步增加一个 `.catch()`,防止遗漏错误造成意想不到的问题。
83+
84+
```javascript
85+
doSomething()
86+
.doAnotherThing()
87+
.doMoreThing()
88+
.catch( err => {
89+
console.log(err);
90+
});
91+
```
92+
93+
在 Node.js7 之后,没有捕获的 Promise 错误会触发一个 Warning,虽然不是很强,但也足够大家发现错误了。

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
范例代码中会使用 ES6 的一些语法,也会混用 ES6 Modules/CommonJS,请大家不要见怪。
2727

28+
本文中所有代码均在 Node.js 8.1 上测试通过。
29+
2830
## 作者介绍
2931

3032
大家好,我叫翟路佳,花名“肉山”,这个名字跟 Dota 没关系,从高中起伴随我到现在。

SUMMARY.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
* [异步的问题](01-2-issue.md)
77
* [异步的发展](01-3-growing.md)
88
* [Promise 方案](02-promise-intro.md)
9-
* [Promise 详解](02-1-promise-basic.md)
10-
* [Promise 进阶](02-2-promise-advanced.md)
9+
* [Promise 入门](02-1-promise-basic.md)
10+
* [Promise 小测验](02-2-promise-test.md)
11+
* [Promise 错误处理](02-2-promise-error.md)
12+
* [Promise 进阶](02-04-promise-advanced.md)
1113
* [Async Functions 方案](03-await-async.md)
1214
* [Async Functions 和 Promise 的异同](03-1-difference-between-await-async-and-promise.md)
1315
* [一起实战吧](04-lets-do-it.md)

0 commit comments

Comments
 (0)