Skip to content

Commit e35fcfd

Browse files
committed
docs(asyce): edit async Generator
1 parent f86bff9 commit e35fcfd

File tree

3 files changed

+112
-37
lines changed

3 files changed

+112
-37
lines changed

docs/async.md

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -742,14 +742,17 @@ async function f() {
742742

743743
```javascript
744744
let body = '';
745-
for await(const data of req) body += data;
746-
const parsed = JSON.parse(body);
747-
console.log('got', parsed);
745+
746+
async function f() {
747+
for await(const data of req) body += data;
748+
const parsed = JSON.parse(body);
749+
console.log('got', parsed);
750+
}
748751
```
749752

750753
上面代码中,`req`是一个 asyncIterable 对象,用来异步读取数据。可以看到,使用`for await...of`循环以后,代码会非常简洁。
751754

752-
如果`next`方法返回的Promise对象被`reject`那么就要用`try...catch`捕捉。
755+
如果`next`方法返回的 Promise 对象被`reject``for await...of`就会报错,要用`try...catch`捕捉。
753756

754757
```javascript
755758
async function () {
@@ -781,6 +784,19 @@ async function () {
781784

782785
在语法上,异步 Generator 函数就是`async`函数与 Generator 函数的结合。
783786

787+
```javascript
788+
async function* gen() {
789+
yield 'hello';
790+
}
791+
const genObj = gen();
792+
genObj.next().then(x => console.log(x));
793+
// { value: 'hello', done: false }
794+
```
795+
796+
上面代码中,`gen`是一个异步 Generator 函数,执行后返回一个异步 Iterator 对象。对该对象调用`next`方法,返回一个 Promise 对象。
797+
798+
下面是另一个例子。
799+
784800
```javascript
785801
async function* readLines(path) {
786802
let file = await fileOpen(path);
@@ -795,14 +811,18 @@ async function* readLines(path) {
795811
}
796812
```
797813

798-
上面代码中,异步操作前面使用`await`关键字标明,即`await`后面的操作,应该返回 Promise 对象。凡是使用`yield`关键字的地方,就是`next`方法的停下来的地方,它后面的表达式的值(即`await file.readLine()`的值),会作为`next()`返回对象的`value`属性,这一点是于同步 Generator 函数一致的。
814+
上面代码中,异步操作前面使用`await`关键字标明,即`await`后面的操作,应该返回 Promise 对象。凡是使用`yield`关键字的地方,就是`next`方法的停下来的地方,它后面的表达式的值(即`await file.readLine()`的值),会作为`next()`返回对象的`value`属性,这一点是与同步 Generator 函数一致的。
815+
816+
异步 Generator 函数内部,能够同时使用`await``yield`命令。可以这样理解,`await`命令用于将外部操作产生的值输入函数内部,`yield`命令用于将函数内部的值输出。
799817

800-
可以像下面这样,使用上面代码定义的异步 Generator 函数
818+
上面代码定义的异步 Generator 函数的用法如下
801819

802820
```javascript
803-
for await (const line of readLines(filePath)) {
804-
console.log(line);
805-
}
821+
(async function () {
822+
for await (const line of readLines(filePath)) {
823+
console.log(line);
824+
}
825+
})()
806826
```
807827

808828
异步 Generator 函数可以与`for await...of`循环结合起来使用。
@@ -815,7 +835,7 @@ async function* prefixLines(asyncIterable) {
815835
}
816836
```
817837

818-
`yield`命令依然是立刻返回的,但是返回的是一个 Promise 对象。
838+
异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的`next`方法,会返回一个 Promise 对象,也就是说,跟在`yield`命令后面的,应该是一个 Promise 对象。
819839

820840
```javascript
821841
async function* asyncGenerator() {
@@ -824,9 +844,34 @@ async function* asyncGenerator() {
824844
yield 'Result: '+ result; // (B)
825845
console.log('Done');
826846
}
847+
848+
const ag = asyncGenerator();
849+
ag.next().then({value, done} => {
850+
// ...
851+
})
827852
```
828853

829-
上面代码中,调用`next`方法以后,会在`B`处暂停执行,`yield`命令立刻返回一个Promise对象。这个Promise对象不同于`A``await`命令后面的那个 Promise 对象。主要有两点不同,一是`A`处的Promise对象`resolve`以后产生的值,会放入`result`变量;二是`B`处的Promise对象`resolve`以后产生的值,是表达式`'Result: ' + result`的值;二是`A`处的 Promise 对象一定先于`B`处的 Promise 对象`resolve`
854+
上面代码中,`ag``asyncGenerator`函数返回的异步 Iterator 对象。调用`ag.next()`以后,`asyncGenerator`函数内部的执行顺序如下。
855+
856+
1. 打印出`Start`
857+
2. `await`命令返回一个 Promise 对象,但是程序不会停在这里,继续往下执行。
858+
3. 程序在`B`处暂停执行,`yield`命令立刻返回一个 Promise 对象,该对象就是`ag.next()`的返回值。
859+
4. `A``await`命令后面的那个 Promise 对象 resolved,产生的值放入`result`变量。
860+
5. `B`处的 Promise 对象 resolved,`then`方法指定的回调函数开始执行,该函数的参数是一个对象,`value`的值是表达式`'Result: ' + result`的值,`done`属性的值是`false`
861+
862+
A 和 B 两行的作用类似于下面的代码。
863+
864+
```javascript
865+
return new Promise((resolve, reject) => {
866+
doSomethingAsync()
867+
.then(result => {
868+
resolve({
869+
value: 'Result: '+result,
870+
done: false,
871+
});
872+
});
873+
});
874+
```
830875

831876
如果异步 Generator 函数抛出错误,会被 Promise 对象`reject`,然后抛出的错误被`catch`方法捕获。
832877

@@ -840,22 +885,22 @@ asyncGenerator()
840885
.catch(err => console.log(err)); // Error: Problem!
841886
```
842887

843-
注意,普通的 async 函数返回的是一个 Promise 对象,而异步 Generator 函数返回的是一个异步Iterator对象。基本上,可以这样理解,`async`函数和异步 Generator 函数,是封装异步操作的两种方法,都用来达到同一种目的。区别在于,前者自带执行器,后者通过`for await...of`执行,或者自己编写执行器。下面就是一个异步 Generator 函数的执行器。
888+
注意,普通的 async 函数返回的是一个 Promise 对象,而异步 Generator 函数返回的是一个异步 Iterator 对象。可以这样理解,async 函数和异步 Generator 函数,是封装异步操作的两种方法,都用来达到同一种目的。区别在于,前者自带执行器,后者通过`for await...of`执行,或者自己编写执行器。下面就是一个异步 Generator 函数的执行器。
844889

845890
```javascript
846-
async function takeAsync(asyncIterable, count=Infinity) {
891+
async function takeAsync(asyncIterable, count = Infinity) {
847892
const result = [];
848893
const iterator = asyncIterable[Symbol.asyncIterator]();
849894
while (result.length < count) {
850-
const {value,done} = await iterator.next();
895+
const {value, done} = await iterator.next();
851896
if (done) break;
852897
result.push(value);
853898
}
854899
return result;
855900
}
856901
```
857902

858-
上面代码中,异步Generator函数产生的异步遍历器,会通过`while`循环自动执行,每当`await iterator.next()`完成,就会进入下一轮循环。
903+
上面代码中,异步 Generator 函数产生的异步遍历器,会通过`while`循环自动执行,每当`await iterator.next()`完成,就会进入下一轮循环。一旦`done`属性变为`true`,就会跳出循环,异步遍历器执行结束
859904

860905
下面是这个自动执行器的一个使用实例。
861906

@@ -875,7 +920,18 @@ f().then(function (result) {
875920
})
876921
```
877922

878-
异步 Generator 函数出现以后,JavaScript就有了四种函数形式:普通函数、async 函数、Generator 函数和异步 Generator 函数。请注意区分每种函数的不同之处。
923+
异步 Generator 函数出现以后,JavaScript 就有了四种函数形式:普通函数、async 函数、Generator 函数和异步 Generator 函数。请注意区分每种函数的不同之处。基本上,如果是一系列按照顺序执行的异步操作(比如读取文件,然后写入新内容,再存入硬盘),可以使用 async 函数;如果是一系列产生相同数据结构的异步操作(比如一行一行读取文件),可以使用异步 Generator 函数。
924+
925+
异步 Generator 函数也可以通过`next`方法的参数,接收外部传入的数据。
926+
927+
```javascript
928+
const writer = openFile('someFile.txt');
929+
writer.next('hello'); // 立即执行
930+
writer.next('world'); // 立即执行
931+
await writer.return(); // 等待写入结束
932+
```
933+
934+
上面代码中,`openFile`是一个异步 Generator 函数。`next`方法的参数,向该函数内部的操作传入数据。每次`next`方法都是同步执行的,最后的`await`命令用于等待整个写入操作结束。
879935

880936
最后,同步的数据结构,也可以使用异步 Generator 函数。
881937

@@ -901,13 +957,14 @@ async function* gen1() {
901957
}
902958

903959
async function* gen2() {
960+
// result 最终会等于 2
904961
const result = yield* gen1();
905962
}
906963
```
907964

908965
上面代码中,`gen2`函数里面的`result`变量,最后的值是`2`
909966

910-
与同步Generator函数一样`for await...of`循环会展开`yield*`
967+
与同步 Generator 函数一样`for await...of`循环会展开`yield*`
911968

912969
```javascript
913970
(async function () {

docs/let.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -605,15 +605,15 @@ window.b // undefined
605605

606606
## global 对象
607607

608-
ES5的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。
608+
ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。
609609

610610
- 浏览器里面,顶层对象是`window`,但 Node 和 Web Worker 没有`window`
611-
- 浏览器和 Web Worker 里面,`self`也指向顶层对象,但是Node没有`self`
611+
- 浏览器和 Web Worker 里面,`self`也指向顶层对象,但是 Node 没有`self`
612612
- Node 里面,顶层对象是`global`,但其他环境都不支持。
613613

614614
同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用`this`变量,但是有局限性。
615615

616-
- 全局环境中,`this`会返回顶层对象。但是,Node模块和ES6模块中`this`返回的是当前模块。
616+
- 全局环境中,`this`会返回顶层对象。但是,Node 模块和 ES6 模块中`this`返回的是当前模块。
617617
- 函数里面的`this`,如果函数不是作为对象的方法运行,而是单纯作为函数运行,`this`会指向顶层对象。但是,严格模式下,这时`this`会返回`undefined`
618618
- 不管是严格模式,还是普通模式,`new Function('return this')()`,总是会返回全局对象。但是,如果浏览器用了CSP(Content Security Policy,内容安全政策),那么`eval``new Function`这些方法都可能无法使用。
619619

@@ -643,20 +643,20 @@ var getGlobal = function () {
643643
垫片库[`system.global`](https://github.com/ljharb/System.global)模拟了这个提案,可以在所有环境拿到`global`
644644

645645
```javascript
646-
// CommonJS的写法
646+
// CommonJS 的写法
647647
require('system.global/shim')();
648648

649-
// ES6模块的写法
649+
// ES6 模块的写法
650650
import shim from 'system.global/shim'; shim();
651651
```
652652

653653
上面代码可以保证各种环境里面,`global`对象都是存在的。
654654

655655
```javascript
656-
// CommonJS的写法
656+
// CommonJS 的写法
657657
var global = require('system.global')();
658658

659-
// ES6模块的写法
659+
// ES6 模块的写法
660660
import getGlobal from 'system.global';
661661
const global = getGlobal();
662662
```

docs/object.md

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,24 @@ let aClone = { ...a };
11011101
let aClone = Object.assign({}, a);
11021102
```
11031103

1104+
上面的例子只是拷贝了对象实例的属性,如果想完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。
1105+
1106+
```javascript
1107+
// 写法一
1108+
const clone1 = {
1109+
__proto__: Object.getPrototypeOf(obj),
1110+
...obj
1111+
};
1112+
1113+
// 写法二
1114+
const clone2 = Object.assign(
1115+
Object.create(Object.getPrototypeOf(obj)),
1116+
obj
1117+
);
1118+
```
1119+
1120+
上面代码中,写法一的`__proto__`属性在非浏览器的环境不一定部署,因此推荐使用写法二。
1121+
11041122
扩展运算符可以用于合并两个对象。
11051123

11061124
```javascript
@@ -1134,6 +1152,16 @@ let newVersion = {
11341152

11351153
上面代码中,`newVersion`对象自定义了`name`属性,其他属性全部复制自`previousVersion`对象。
11361154

1155+
如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值。
1156+
1157+
```javascript
1158+
let aWithDefaults = { x: 1, y: 2, ...a };
1159+
// 等同于
1160+
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
1161+
// 等同于
1162+
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
1163+
```
1164+
11371165
与数组的扩展运算符一样,对象的扩展运算符后面可以跟表达式。
11381166

11391167
```javascript
@@ -1150,14 +1178,10 @@ const obj = {
11501178
// { a: 1 }
11511179
```
11521180

1153-
如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值
1181+
如果扩展运算符的参数是`null``undefined`,这两个值会被忽略,不会报错
11541182

11551183
```javascript
1156-
let aWithDefaults = { x: 1, y: 2, ...a };
1157-
// 等同于
1158-
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
1159-
// 等同于
1160-
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
1184+
let emptyObject = { ...null, ...undefined }; // 不报错
11611185
```
11621186

11631187
扩展运算符的参数对象之中,如果有取值函数`get`,这个函数是会执行的。
@@ -1182,15 +1206,9 @@ let runtimeError = {
11821206
};
11831207
```
11841208

1185-
如果扩展运算符的参数是`null``undefined`,这两个值会被忽略,不会报错。
1186-
1187-
```javascript
1188-
let emptyObject = { ...null, ...undefined }; // 不报错
1189-
```
1190-
11911209
## Object.getOwnPropertyDescriptors()
11921210

1193-
ES5有一个`Object.getOwnPropertyDescriptor`方法,返回某个对象属性的描述对象(descriptor)。
1211+
ES5 一个`Object.getOwnPropertyDescriptor`方法,返回某个对象属性的描述对象(descriptor)。
11941212

11951213
```javascript
11961214
var obj = { p: 'a' };

0 commit comments

Comments
 (0)