@@ -742,14 +742,17 @@ async function f() {
742
742
743
743
``` javascript
744
744
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
+ }
748
751
```
749
752
750
753
上面代码中,` req ` 是一个 asyncIterable 对象,用来异步读取数据。可以看到,使用` for await...of ` 循环以后,代码会非常简洁。
751
754
752
- 如果` next ` 方法返回的Promise对象被 ` reject ` ,那么就要用 ` try...catch ` 捕捉。
755
+ 如果` next ` 方法返回的 Promise 对象被 ` reject ` ,` for await...of ` 就会报错,要用 ` try...catch ` 捕捉。
753
756
754
757
``` javascript
755
758
async function () {
@@ -781,6 +784,19 @@ async function () {
781
784
782
785
在语法上,异步 Generator 函数就是` async ` 函数与 Generator 函数的结合。
783
786
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
+
784
800
``` javascript
785
801
async function * readLines (path ) {
786
802
let file = await fileOpen (path);
@@ -795,14 +811,18 @@ async function* readLines(path) {
795
811
}
796
812
```
797
813
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 ` 命令用于将函数内部的值输出。
799
817
800
- 可以像下面这样,使用上面代码定义的异步 Generator 函数 。
818
+ 上面代码定义的异步 Generator 函数的用法如下 。
801
819
802
820
``` 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
+ })()
806
826
```
807
827
808
828
异步 Generator 函数可以与` for await...of ` 循环结合起来使用。
@@ -815,7 +835,7 @@ async function* prefixLines(asyncIterable) {
815
835
}
816
836
```
817
837
818
- ` yield ` 命令依然是立刻返回的,但是返回的是一个 Promise 对象。
838
+ 异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的 ` next ` 方法,会返回一个 Promise 对象,也就是说,跟在 ` yield ` 命令后面的,应该是一个 Promise 对象。
819
839
820
840
``` javascript
821
841
async function * asyncGenerator () {
@@ -824,9 +844,34 @@ async function* asyncGenerator() {
824
844
yield ' Result: ' + result; // (B)
825
845
console .log (' Done' );
826
846
}
847
+
848
+ const ag = asyncGenerator ();
849
+ ag .next ().then ({value, done} => {
850
+ // ...
851
+ })
827
852
```
828
853
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
+ ```
830
875
831
876
如果异步 Generator 函数抛出错误,会被 Promise 对象` reject ` ,然后抛出的错误被` catch ` 方法捕获。
832
877
@@ -840,22 +885,22 @@ asyncGenerator()
840
885
.catch (err => console .log (err)); // Error: Problem!
841
886
```
842
887
843
- 注意,普通的 async 函数返回的是一个 Promise 对象,而异步 Generator 函数返回的是一个异步Iterator对象。基本上, 可以这样理解,` async ` 函数和异步 Generator 函数,是封装异步操作的两种方法,都用来达到同一种目的。区别在于,前者自带执行器,后者通过` for await...of ` 执行,或者自己编写执行器。下面就是一个异步 Generator 函数的执行器。
888
+ 注意,普通的 async 函数返回的是一个 Promise 对象,而异步 Generator 函数返回的是一个异步 Iterator 对象。 可以这样理解,async 函数和异步 Generator 函数,是封装异步操作的两种方法,都用来达到同一种目的。区别在于,前者自带执行器,后者通过` for await...of ` 执行,或者自己编写执行器。下面就是一个异步 Generator 函数的执行器。
844
889
845
890
``` javascript
846
- async function takeAsync (asyncIterable , count = Infinity ) {
891
+ async function takeAsync (asyncIterable , count = Infinity ) {
847
892
const result = [];
848
893
const iterator = asyncIterable[Symbol .asyncIterator ]();
849
894
while (result .length < count) {
850
- const {value ,done } = await iterator .next ();
895
+ const {value , done } = await iterator .next ();
851
896
if (done) break ;
852
897
result .push (value);
853
898
}
854
899
return result;
855
900
}
856
901
```
857
902
858
- 上面代码中,异步Generator函数产生的异步遍历器 ,会通过` while ` 循环自动执行,每当` await iterator.next() ` 完成,就会进入下一轮循环。
903
+ 上面代码中,异步 Generator 函数产生的异步遍历器 ,会通过` while ` 循环自动执行,每当` await iterator.next() ` 完成,就会进入下一轮循环。一旦 ` done ` 属性变为 ` true ` ,就会跳出循环,异步遍历器执行结束 。
859
904
860
905
下面是这个自动执行器的一个使用实例。
861
906
@@ -875,7 +920,18 @@ f().then(function (result) {
875
920
})
876
921
```
877
922
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 ` 命令用于等待整个写入操作结束。
879
935
880
936
最后,同步的数据结构,也可以使用异步 Generator 函数。
881
937
@@ -901,13 +957,14 @@ async function* gen1() {
901
957
}
902
958
903
959
async function * gen2 () {
960
+ // result 最终会等于 2
904
961
const result = yield * gen1 ();
905
962
}
906
963
```
907
964
908
965
上面代码中,` gen2 ` 函数里面的` result ` 变量,最后的值是` 2 ` 。
909
966
910
- 与同步Generator函数一样 ,` for await...of ` 循环会展开` yield* ` 。
967
+ 与同步 Generator 函数一样 ,` for await...of ` 循环会展开` yield* ` 。
911
968
912
969
``` javascript
913
970
(async function () {
0 commit comments