Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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)

AltStyle によって変換されたページ (->オリジナル) /