Promise
新界 promise 对象,在其中写入需要异步的代码
|
注意
|
上面代码中,调用 resolve(1) 以后,后面的 console.log(2) 还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
一般来说,调用 resolve 或 reject 以后, Promise 的使命就完成了,后继操作应该放到 then 方法里面,而不应该直接写在 resolve 或 reject 的后面。所以,最好在它们前面加上 return 语句,这样就不会有意外。
|
Generator函数
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
|
上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。
然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。
下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
|
上面代码一共调用了四次next方法。
第一次调用, Generator 函数开始执行,直到遇到第一个 yield 表达式为止。 next 方法返回一个对象,它的 value 属性就是当前 yield 表达式的值 hello , done 属性的值 false ,表示遍历还没有结束。
第二次调用, Generator 函数从上次 yield 表达式停下的地方,一直执行到下一个 yield 表达式。 next 方法返回的对象的 value 属性就是当前 yield 表达式的值 world , done 属性的值 false ,表示遍历还没有结束。
第三次调用, Generator 函数从上次 yield 表达式停下的地方,一直执行到 return 语句(如果没有 return 语句,就执行到函数结束)。 next 方法返回的对象的 value 属性,就是紧跟在 return 语句后面的表达式的值(如果没有 return 语句,则 value 属性的值为 undefined ), done 属性的值 true ,表示遍历已经结束。
第四次调用,此时 Generator 函数已经运行完毕, next 方法返回对象的 value 属性为 undefined , done 属性为 true 。以后再调用 next 方法,返回的都是这个值。
总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的 next 方法,就会返回一个有着 value 和 done 两个属性的对象。 value 属性表示当前的内部状态的值,是 yield 表达式后面那个表达式的值; done 属性是一个布尔值,表示是否遍历结束。
async函数
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
|
上面代码的函数 gen 可以写成 async 函数,就是下面这样。
|
一比较就会发现, async 函数就是将 Generator 函数的星号 (*) 替换成 async ,将 yield 替换成 await ,仅此而已。async 函数对 Generator 函数的改进,体现在以下四点。
(1)内置执行器。
Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
|
上面的代码调用了 asyncReadFile 函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用 next 方法,或者用 co 模块,才能真正执行,得到最后结果。
(2)更好的语义。
async 和 await ,比起星号和 yield ,语义更清楚了。 async 表示函数里有异步操作, await 表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。
co 模块约定, yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)返回值是 Promise。
async 函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用 then 方法指定下一步的操作。
进一步说, async 函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部then命令的语法糖。
下面是一个例子。
|
Promise对象的状态变化
async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。
下面是一个例子。
|
上面代码中,函数 getTitle 内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行 then 方法里面的 console.log 。
await 命令
正常情况下, await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
|
上面代码中, await 命令的参数是数值 123 ,这时等同于 return 123 。
另一种情况是, await 命令后面是一个 thenable 对象(即定义了 then 方法的对象),那么 await 会将其等同于 Promise 对象。
|
上面代码中, await 命令后面是一个 Sleep 对象的实例。这个实例不是 Promise 对象,但是因为定义了 then 方法, await 会将其视为 Promise 处理。
参考
Promise 对象
Generator 函数的语法
async函数
- 本文作者: luckyship
- 本文链接: https://luckyship.github.io/2020/10/22/2020-10-22-es6-async-methods/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
