当前位置:   article > 正文

ES6+--》熟知JS中的async函数_箭头函数 async

箭头函数 async

目录

async函数

await 表达式

async使用形式

async读取文件

async发送AJAX请求

与生成器(Generator)相比


async函数

async函数的返回值为 promise 对象,promise对象的结果由async函数执行的返回值决定。async函数能使得异步操作变得更加方便,简而言之就是 Generator 的语法糖

定义async函数,特点是即便函数内部返回结果不是promise对象,调用函数其最后的返回结果依然是promise对象,代码如下:

如果返回的结果不是 Promise 对象的情况下:

  1. <script>
  2. async function fn(){
  3. // 返回的结果是字符串
  4. // return '123'
  5. // // 返回的结果是undefined
  6. // return;
  7. // 返回的结果是抛出一个异常
  8. throw new 'error'
  9. }
  10. const result = fn()
  11. console.log(result);
  12. </script>

如果返回的结果是 Promise 对象时,我们正常使用 then 方法即可,如下:

  1. <script>
  2. async function fn(){
  3. return new Promise((resolve,reject)=>{
  4. // resolve('成功的数据')
  5. reject('失败的数据')
  6. })
  7. }
  8. const result = fn()
  9. // 调用 then 方法
  10. result.then((value)=>{
  11. console.log(value);
  12. },(reason)=>{
  13. console.log(reason); // 打印失败的数据
  14. })
  15. </script>

await 表达式

通过上文的对 async 介绍,感觉其功能有点鸡肋,其实恰恰不是,而是 async 需要搭配 await 一起使用才能达到语法糖的效果。

await的特点

await必须写在 async 函数中

await右侧的表达式一般为 promise 对象

await返回的是 promise 成功的值

await的 promise 失败了,就会抛出异常,需要通过 try...catch捕获处理

说白了:await就相当于 then 方法的第一个回调函数,只返回成功的值,失败的值需要 try...catch来捕获。

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

  1. <script>
  2. const p = new Promise((resolve,reject)=>{
  3. // resolve('用户数据')
  4. reject('用户加载数据失败了')
  5. })
  6. async function fn(){
  7. // 为防止promise是失败的状态,加上try...catch进行异常捕获
  8. try {
  9. // await 返回的结果就是 promise 返回成功的值
  10. let result = await p
  11. console.log(result);
  12. } catch (error) {
  13. console.log(error);//因为是失败的状态,所以打印:用户加载数据失败了
  14. }
  15. }
  16. fn()
  17. </script>

总结

(1)await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

(2)如果有多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

比如:await Promise.all([a(), b()]),这里简单提一下

(3)await命令只能用在async函数之中,如果用在普通函数,就会报错。

(4)(理解一下async的运行原理) async 函数可以保留运行堆栈,普通函数内部运行一个异步任务时,如果异步任务运行结束普通函数可能早就运行完了,异步任务的上下文环境已经消失了,如果异步任务报错,错误堆栈将不包括普通函数;而async函数内部的异步任务运行时,async函数是暂停执行的,所以一旦async函数内部的异步任务运行报错,错误堆栈将包括async函数。

async使用形式

  1. // 函数声明
  2. async function foo() {}
  3. // 函数表达式
  4. const foo = async function () {};
  5. // 对象的方法
  6. let obj = { async foo() {} };
  7. obj.foo().then(...)
  8. // Class 的方法
  9. class Storage {
  10. constructor() {
  11. this.cachePromise = caches.open('avatars');
  12. }
  13. async getAvatar(name) {
  14. const cache = await this.cachePromise;
  15. return cache.match(`/avatars/${name}.jpg`);
  16. }
  17. }
  18. const storage = new Storage();
  19. storage.getAvatar('jake').then(…);
  20. // 箭头函数
  21. const foo = async () => {};

async读取文件

和之前讲解的 promise 读取文件内容 一样,我们也可以使用async进行文件的读取,代码如下:

  1. // 1.引入 fs 模块
  2. const fs = require('fs')
  3. // 2.读取文件
  4. function index(){
  5. return new Promise((resolve,reject)=>{
  6. fs.readFile('./index.md',(err,data)=>{
  7. // 如果失败
  8. if(err) reject(err)
  9. // 如果成功
  10. resolve(data)
  11. })
  12. })
  13. }
  14. function index1(){
  15. return new Promise((resolve,reject)=>{
  16. fs.readFile('./index1.md',(err,data)=>{
  17. // 如果失败
  18. if(err) reject(err)
  19. // 如果成功
  20. resolve(data)
  21. })
  22. })
  23. }
  24. function index2(){
  25. return new Promise((resolve,reject)=>{
  26. fs.readFile('./index2.md',(err,data)=>{
  27. // 如果失败
  28. if(err) reject(err)
  29. // 如果成功
  30. resolve(data)
  31. })
  32. })
  33. }
  34. // 3.声明一个 async 函数
  35. async function fn(){
  36. let i = await index()
  37. let i1 = await index1()
  38. let i2 = await index2()
  39. console.log(i.toString());
  40. console.log(i1.toString());
  41. console.log(i2.toString());
  42. }
  43. fn()

async发送AJAX请求

和之前讲解 promise发送ajax请求 一样,我们也可以使用async进行发送ajax请求,代码如下:

  1. <script>
  2. // 发送 AJAX请求,返回的结果是 Promise 对象
  3. function sendAjax(url){
  4. return new Promise((resolve,reject)=>{
  5. // 创建对象
  6. const x = new XMLHttpRequest()
  7. // 初始化
  8. x.open('GET',url)
  9. // 发送
  10. x.send()
  11. // 事件绑定
  12. x.onreadystatechange = function(){
  13. if(x.readyState === 4){
  14. if(x.status >= 200 && x.status < 300){
  15. // 如果响应成功
  16. resolve(x.response)
  17. // 如果响应失败
  18. reject(x.status)
  19. }
  20. }
  21. }
  22. })
  23. }
  24. // promise then 方法测试
  25. // const result = sendAjax("https://ai.baidu.com/").then(value=>{
  26. // console.log(value);
  27. // },reason=>{})
  28. // async 与 await 测试
  29. async function fn(){
  30. // 发送 AJAX 请求
  31. let result = await sendAjax("https://ai.baidu.com/")
  32. console.log(result);
  33. }
  34. fn()
  35. </script>

与生成器(Generator)相比

我们发现 async与await之间的关系 和 Generator与yield之间的关系十分类似,不熟悉Generator的朋友可以看一下我之前的文章:生成器讲解 ;一比较就发现: async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。代码比较如下:

  1. <script>
  2. // Generator 函数
  3. function * person() {
  4. console.log('hello world');
  5. yield '第一分隔线'
  6. console.log('hello world 1');
  7. yield '第二分隔线'
  8. console.log('hello world 2');
  9. yield '第三分隔线'
  10. }
  11. let iterator = person()
  12. // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行
  13. iterator.next()
  14. iterator.next()
  15. iterator.next()
  16. // async函数
  17. const person1 = async function (){
  18. console.log('hello world');
  19. await '第一分隔线'
  20. console.log('hello world 1');
  21. await '第二分隔线'
  22. console.log('hello world 2');
  23. await '第三分隔线'
  24. }
  25. person1()
  26. </script>

async函数的实现原理就是将 Generator 函数和自动执行器包装在一个函数里。

  1. <script>
  2. async function fn(args) {}
  3. // 等同于
  4. function fn(args) {
  5. // spawn函数就是自动执行器
  6. return spawn(function* () {});
  7. }
  8. </script>

我们可以分析一下 Generator 和 async 代码的书写特点和风格:

  1. <script>
  2. // Generator 函数
  3. function Generator(a, b) {
  4. return spawn(function*() {
  5. let r = null;
  6. try {
  7. for(let k of b) {
  8. r = yield k(a);
  9. }
  10. } catch(e) {
  11. /* 忽略错误,继续执行 */
  12. }
  13. return r;
  14. });
  15. }
  16. // async 函数
  17. async function async(a, b) {
  18. let r = null;
  19. try {
  20. for(let k of b) {
  21. r = await k(a);
  22. }
  23. } catch(e) {
  24. /* 忽略错误,继续执行 */
  25. }
  26. return r;
  27. }
  28. </script>

所以 async 函数的实现符合语义也很简洁,不用写Generator的自动执行器,改在语言底层提供,因此代码量少。 

从上文代码我们可以总结以下几点

(1)Generator函数执行需要借助执行器,而async函数自带执行器,即async不需要像生成器一样需要借助 next 方法才能执行,而是会自动执行。

(2)相比于生成器函数,我们可以看到 async 函数的语义更加清晰

(3)上面就说了,async函数可以接受Promise或者其他原始类型,而生成器函数yield命令后面只能是Promise对象或者Thunk函数。

(4)async函数返回值只能是Promise对象,而生成器函数返回值是 Iterator 对象

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/148351
推荐阅读
相关标签
  

闽ICP备14008679号