Skip to content

Commit 98ccaaf

Browse files
committed
基本完成初稿,先提交了吧。
1 parent 3a18abf commit 98ccaaf

9 files changed

+1526
-40
lines changed

Diff for: .gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@
44
node_modules
55

66
# test
7-
test
7+
test
8+
9+
# build
10+
build

Diff for: 03-1-async-function-vs-promise.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Async Function VS Promise
33

44
## 异步函数的优势
55

6-
异步函数对异步编程来说,是很大的进步。尤其在 `try/catch/throw` 方面,异步函数可以延续以前的标准写法,优势非常大。
6+
异步函数对异步编程来说,有非常很大的提升。尤其在 `try/catch/throw` 方面,异步函数可以延续以前的标准写法,优势非常大。
77

88
## Promise 的优势
99

@@ -13,7 +13,7 @@ Async Function VS Promise
1313

1414
异步函数返回的是一个 Promise 对象;`await` 关键字只能等待 Promise 对象完成操作。
1515

16-
所以关于 Promise 的知识都还有效,大家也必须学习 Promise,才能更好的使用异步函数。
16+
所以 Promise 的知识都还有效,大家也必须学习 Promise,才能更好的使用异步函数。
1717

1818
### Promise 能更好的提供队列操作,并且在对象之间传递
1919

Diff for: 03-async-function.md

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
Async Function
2+
========
3+
4+
Async Function,即异步函数,为异步编程带来了非常大的提升,瞬间把开发效率和维护效率提升了一个数量级。
5+
6+
它的用法非常简单,只要用 `async` 关键字声明一个函数为“异步函数”,这个函数的内部就可以使用 await 关键字,让其中的语句等待异步执行的结果,然后再继续执行。我们还是用代码来说话吧:
7+
8+
```javascript
9+
function resolveAfter2Seconds(x) {
10+
return new Promise(resolve => {
11+
setTimeout(() => {
12+
resolve(x);
13+
}, 2000);
14+
});
15+
}
16+
17+
async function f1() {
18+
var x = await resolveAfter2Seconds(10);
19+
console.log(x);
20+
}
21+
f1();
22+
23+
// 输出:
24+
// (2秒后)10
25+
```
26+
27+
这段代码来自 [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)。里面先声明了 `resolveAfter2Seconds` 函数,执行它会返回一个 Promise 对象,等待2秒钟之后完成。然后声明了异步函数 `f1`,里面只有两行代码,第一行用 `await` 表示要等后面的 Promise 完成,再进行下一步;于是2秒之后,输出了“10”。
28+
29+
这段代码比较短,不太能体现异步函数的价值,我们改写一下查找最大文件的代码试试看:
30+
31+
```javascript
32+
const fs = require('./FileSystem');
33+
34+
async function findLargest(dir) {
35+
let files = await fs.readdir(dir);
36+
let stats = [];
37+
for (let i = 0, len = files.length; i < len; i++) {
38+
stats.push(await fs.stat(files[i]));
39+
}
40+
let file = stats
41+
.filter( stat => stat.isFile() )
42+
.reduce( (memo, stat) => {
43+
if (memo.size > stat.size) return memo;
44+
return stat;
45+
});
46+
return file;
47+
}
48+
49+
findLargest('path/to/dir')
50+
.then(file => {
51+
console.log(file);
52+
});
53+
```
54+
55+
怎么样,是不是异常清晰明了,连代码量都减少了很多。而且,因为每次 `await` 都会等待后面的异步函数完成,所以我们还无意间写出了生成队列的代码。当然你可能不希望要队列,毕竟都异步了,队列的吸引力实在不大,那么我们只需要把它改成下面这种样子就行了:
56+
57+
```javascript
58+
let stats = await Promise.all(files.map( file => fs.stat(file) ));
59+
```
60+
61+
酷不酷!想不想学?
62+
63+
## 设计
64+
65+
见识过异步函数的强大之后,我们来捋一捋一下它的具体设计。
66+
67+
异步函数主要由两部分组成:
68+
69+
### `async`
70+
71+
声明一个函数是异步函数。执行异步函数会返回一个 Promise 实例。异步函数的返回值会作为 `.then()` 的参数向后传递。
72+
73+
`async` 的语法比较简单,就在普通函数前面加个 `async` 而已。
74+
75+
### `await`
76+
77+
`await` 操作符只能用在异步函数的内部。表示等待一个 Promise 完成,然后返回其返回值。语法是这样的:
78+
79+
```javascript
80+
[return_value] = await expression;
81+
```
82+
83+
**return_value 返回值**:Promise 执行器的返回值
84+
**expression 表达式**:Promise 对象,其它类型会使用 `Promise.resolve()` 转换
85+
86+
使用 `await` 之后,异步函数会暂停执行,等待表达式里的 Promise 完成。`resolve` 之后,返回 Promise 执行器的返回值,然后继续执行。如果 Promise 被 `rejected`,就抛出异常。
87+
88+
## 捕获错误
89+
90+
异步函数最大的改进其实就在捕获错误这里。它可以直接使用 `try/catch/throw` 就想我们之前那样。
91+
92+
比如,一款前后端分离的应用,比如论坛块,需要用户登录,所以在初始化的时候就会去后端请求用户信息,如果返回了,就继续加载用户关注列表;如果 401,就让用户登录。用 Promise 的话,我们这样做:
93+
94+
```javascript
95+
function getMyProfile() {
96+
return fetch('api/me')
97+
.then(response => {
98+
if (response.ok) {
99+
return response.json();
100+
}
101+
})
102+
.then(profile => {
103+
global.profile = profile
104+
})
105+
.catch( err => {
106+
if (err.statusCode === 401) {
107+
location.href = '#/login';
108+
}
109+
})
110+
}
111+
```
112+
113+
这样做也不是不可以,但是如果业务逻辑越来越复杂,队列也会越来越长,也许每一步都需要处理错误,那么队列就会变得难以维护。
114+
115+
如果用异步函数就会简单很多:
116+
117+
```javascript
118+
async function getMyProfile() {
119+
let profile;
120+
try {
121+
profile = await fetch('api/me');
122+
global.profile = profile;
123+
} catch (e) {
124+
if (e.statusCode === 401) {
125+
location.href = '#/login';
126+
}
127+
}
128+
}
129+
```
130+
131+
另外,如果你真的捕获到错误,你会发现,它的堆栈信息是连续的,甚至可以回溯到调用异步函数的语句,继而可以审查所有堆栈里的变量。这对调试程序带来的帮助非常巨大。
132+
133+
## 普及率
134+
135+
[![Async Function 的普及率](http://images.gitbook.cn/000af860-5801-11e7-92d5-13bc6466d9ae)](http://caniuse.com/#search=async%20function)
136+
截图于:2017-06-23

Diff for: 03-await-async.md

-36
This file was deleted.

Diff for: 10-review.md

+7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@
3535

3636
## 参考阅读
3737

38+
* [MDN Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
39+
* [MDN Promise 中文](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise)
40+
* [阮一峰:ECMAScript 6 入门 - Promise 对象](http://es6.ruanyifeng.com/#docs/promise)
41+
* [[翻译] We have a problem with promises](http://fex.baidu.com/blog/2015/07/we-have-a-problem-with-promises/)
42+
* [MDN Generator](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator)
43+
* [Async Function](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function)
44+
* [await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)
3845
* [让微信小程序支持 ES6 的 Promise 特性](https://haojen.github.io/2016/11/23/wechat-app-promise/)
3946
* [util.promisify() in Node.js v8](http://farzicoder.com/util-promisify-in-Node-js-v8/)
4047
* [util.promisify 官方文档](https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original)

Diff for: SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* [Promise 错误处理](02-2-promise-error.md)
1212
* [Promise 进阶](02-04-promise-advanced.md)
1313
* [Async Functions 方案](03-await-async.md)
14-
* [Async Functions VS Promise](03-1-difference-between-await-async-and-promise.md)
14+
* [Async Functions VS Promise](03-1-async-function-vs-promise.md)
1515
* [一起实战吧](04-lets-do-it.md)
1616
* [降级](04-1-downgrade.md)
1717
* [小程序](04-2-xiaochengxu.md)

Diff for: gulpfile.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const fs = require('fs');
2+
const util = require('util');
3+
const gulp = require('gulp');
4+
const del = require('del');
5+
const sequence = require('run-sequence');
6+
const concat = require('gulp-concat');
7+
8+
const TO = 'build/';
9+
const readFile = util.promisify(fs.readFile);
10+
11+
gulp.task('clear', () => {
12+
del(TO);
13+
});
14+
15+
gulp.task('gitchat', async () => {
16+
let summary = await readFile('./SUMMARY.md');
17+
let chapters = /\]\(([^)]+\.md)\)/g[Symbol.match](summary)
18+
.map(chapter => chapter.slice(2, -1));
19+
return gulp.src(chapters)
20+
.pipe(concat('all.md', {
21+
newLine: '\n\r'
22+
}))
23+
.pipe(gulp.dest(TO + 'gitchat/'));
24+
});
25+
26+
gulp.task('default', callback => {
27+
sequence(
28+
'clear',
29+
'gitchat',
30+
callback
31+
);
32+
});

0 commit comments

Comments
 (0)