diff --git a/docs/async.md b/docs/async.md index accdbb4..cf36a34 100644 --- a/docs/async.md +++ b/docs/async.md @@ -742,9 +742,9 @@ function* somethingAsync(x) { ### 含义 -ES7提供了`async`函数,使得异步操作变得更加方便。`async`函数是什么?一句话,`async`函数就是Generator函数的语法糖。 +ES2017 标准提供了`async`函数,使得异步操作变得更加方便。 -前文有一个Generator函数,依次读取两个文件。 +`async`函数是什么?一句话,`async`函数就是 Generator 函数的语法糖。前文有一个 Generator 函数,依次读取两个文件。 ```javascript var fs = require('fs'); @@ -777,25 +777,25 @@ var asyncReadFile = async function (){ }; ``` -一比较就会发现,`async`函数就是将Generator函数的星号(`*`)替换成`async`,将`yield`替换成`await`,仅此而已。 +一比较就会发现,`async`函数就是将 Generator 函数的星号(`*`)替换成`async`,将`yield`替换成`await`,仅此而已。 `async`函数对 Generator 函数的改进,体现在以下四点。 -(1)内置执行器。Generator函数的执行必须靠执行器,所以才有了`co`模块,而`async`函数自带执行器。也就是说,`async`函数的执行,与普通函数一模一样,只要一行。 +(1)内置执行器。Generator 函数的执行必须靠执行器,所以才有了`co`模块,而`async`函数自带执行器。也就是说,`async`函数的执行,与普通函数一模一样,只要一行。 ```javascript var result = asyncReadFile(); ``` -上面的代码调用了`asyncReadFile`函数,然后它就会自动执行,输出最后结果。这完全不像Generator函数,需要调用`next`方法,或者用`co`模块,才能得到真正执行,得到最后结果。 +上面的代码调用了`asyncReadFile`函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用`next`方法,或者用`co`模块,才能得到真正执行,得到最后结果。 (2)更好的语义。`async`和`await`,比起星号和`yield`,语义更清楚了。`async`表示函数里有异步操作,`await`表示紧跟在后面的表达式需要等待结果。 -(3)更广的适用性。 `co`模块约定,`yield`命令后面只能是Thunk函数或Promise对象,而`async`函数的`await`命令后面,可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。 +(3)更广的适用性。 `co`模块约定,`yield`命令后面只能是 Thunk 函数或 Promise 对象,而`async`函数的`await`命令后面,可以是Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。 -(4)返回值是Promise。`async`函数的返回值是Promise对象,这比Generator函数的返回值是Iterator对象方便多了。你可以用`then`方法指定下一步的操作。 +(4)返回值是 Promise。`async`函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用`then`方法指定下一步的操作。 -进一步说,`async`函数完全可以看作多个异步操作,包装成的一个Promise对象,而`await`命令就是内部`then`命令的语法糖。 +进一步说,`async`函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而`await`命令就是内部`then`命令的语法糖。 ### 语法 @@ -816,7 +816,7 @@ f().then(v => console.log(v)) 上面代码中,函数`f`内部`return`命令返回的值,会被`then`方法回调函数接收到。 -`async`函数内部抛出错误,会导致返回的Promise对象变为`reject`状态。抛出的错误对象会被`catch`方法回调函数接收到。 +`async`函数内部抛出错误,会导致返回的 Promise 对象变为`reject`状态。抛出的错误对象会被`catch`方法回调函数接收到。 ```javascript async function f() { @@ -830,7 +830,7 @@ f().then( // Error: 出错了 ``` -(2)`async`函数返回的Promise对象,必须等到内部所有`await`命令的Promise对象执行完,才会发生状态改变。也就是说,只有`async`函数内部的异步操作执行完,才会执行`then`方法指定的回调函数。 +(2)`async`函数返回的 Promise 对象,必须等到内部所有`await`命令的Promise对象执行完,才会发生状态改变,除非遇到`return`语句或者抛出错误。也就是说,只有`async`函数内部的异步操作执行完,才会执行`then`方法指定的回调函数。 下面是一个例子。 @@ -844,7 +844,9 @@ getTitle('https://tc39.github.io/ecma262/').then(console.log) // "ECMAScript 2017 Language Specification" ``` -(3)正常情况下,`await`命令后面是一个Promise对象。如果不是,会被转成一个立即`resolve`的Promise对象。 +上面代码中,函数`getTitle`内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行`then`方法里面的`console.log`。 + +(3)正常情况下,`await`命令后面是一个 Promise 对象。如果不是,会被转成一个立即`resolve`的 Promise 对象。 ```javascript async function f() { @@ -1008,8 +1010,6 @@ function spawn(genF) { } ``` -`async`函数是非常新的语法功能,新到都不属于 ES6,而是属于 ES7。目前,它仍处于提案阶段,但是转码器`Babel`和`regenerator`都已经支持,转码后就能使用。 - ### async 函数的用法 `async`函数返回一个Promise对象,可以使用`then`方法添加回调函数。当函数执行的时候,一旦遇到`await`就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。 @@ -1047,7 +1047,7 @@ async function asyncPrint(value, ms) { asyncPrint('hello world', 50); ``` -上面代码指定50毫秒以后,输出"hello world"。 +上面代码指定50毫秒以后,输出`hello world`。 Async函数有多种使用形式。 @@ -1323,7 +1323,7 @@ async function logInOrder(urls) { ## 异步遍历器 -《遍历器》一章说过,Iterator接口是一种数据遍历的协议,只要调用遍历器对象的`next`方法,就会得到一个表示当前成员信息的对象`{value, done}`。其中,`value`表示当前的数据的值,`done`是一个布尔值,表示遍历是否结束。 +《遍历器》一章说过,Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的`next`方法,就会得到一个表示当前成员信息的对象`{value, done}`。其中,`value`表示当前的数据的值,`done`是一个布尔值,表示遍历是否结束。 这隐含着规定,`next`方法是同步的,只要调用就必须立刻返回值。也就是说,一旦执行`next`方法,就必须同步地得到`value`和`done`这两方面的信息。这对于同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator函数里面的异步操作,返回一个Thunk函数或者Promise对象,即`value`属性是一个Thunk函数或者Promise对象,等待以后返回真正的值,而`done`属性则还是同步产生的。 @@ -1587,3 +1587,4 @@ async function* gen2() { // a // b ``` + diff --git a/docs/set-map.md b/docs/set-map.md index 133f64e..bff19a6 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -166,7 +166,7 @@ Set结构的实例有四个遍历方法,可以用于遍历成员。 **(1)`keys()`,`values()`,`entries()`** -`key`方法、`value`方法、`entries`方法返回的都是遍历器对象(详见《Iterator对象》一章)。由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以`key`方法和`value`方法的行为完全一致。 +`keys`方法、`values`方法、`entries`方法返回的都是遍历器对象(详见《Iterator 对象》一章)。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以`keys`方法和`values`方法的行为完全一致。 ```javascript let set = new Set(['red', 'green', 'blue']); diff --git a/docs/symbol.md b/docs/symbol.md index 0b4628d..be860ee 100644 --- a/docs/symbol.md +++ b/docs/symbol.md @@ -303,7 +303,7 @@ let obj = { }; Reflect.ownKeys(obj) -// [Symbol(my_key), 'enum', 'nonEnum'] +// ["enum", "nonEnum", Symbol(my_key)] ``` 由于以 Symbol 值作为名称的属性,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。