• 【async/await】--异步编程最终解决方案


    前言

    😎😎欢迎来到我的博客😎😎
    📔博主是一名大学在读本科生,主要学习方向是前端😊。
    🍭目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏🤩
    🛠目前正在学习的是🔥 R e a c t 框 架 React框架 React🔥,中间夹杂了一些基础知识的回顾⌨️
    🌈博客主页👉codeMak1r.的博客
    ➕关注👍点赞📂收藏

    🕹坚持创作✏️,一起学习📖,码出未来👨🏻‍💻!

    🌟async函数

    async关键字用来标识一个函数,async关键字标识过的函数为async函数。

    1. 函数的返回值为promise对象
    2. promise对象的结果由async函数执行的返回值决定
    3. async函数与promise.then()方法返回值情况类似
    async函数返回值async函数内部
    promise对象,对象的状态为成功,成功的值由async函数内部的返回值决定一个非promise类型的返回值
    promise对象,状态为成功,成功的值为undefined。没有声明return
    promise对象,状态为成功,成功的值为123.return 123;
    promise对象,状态由返回值中的promise对象状态决定
    对象的值由返回值中的promise对象的值决定
    一个promise类型的返回值
    promise对象,状态为失败;
    失败的值为‘error’。
    return Promise.reject(‘error’)
    promise对象,状态为失败,失败的值为‘Oh NO!’throw ‘Oh NO!’
    <body>
      <script>
        async function main() {
          return Promise.reject('error')
        }
    
        let result = main()
        console.log(result)
      </script>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    打印台显示:

    result是一个prmoise类型的对象,状态为失败,值为error。


    <body>
      <script>
        async function main() {
          throw 'Oh NO!'
        }
    
        let result = main()
        console.log(result)
      </script>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    打印台显示:

    result是一个promise类型的对象,状态为失败,值为‘Oh NO!’。

    🌟await表达式

    1. await右侧的表达式一般为promise对象,但也可以是其他的值;
    2. 如果表达式是promise对象,await返回的是promise成功的值;
    3. 如果表达式是其他值,直接将此值作为await的返回值。

    注意⚠️:

    1. await必须写在async函数中,但async函数中可以没有await;
    2. 如果await 的promise失败了,就会抛出异常,需要通过try…catch捕获处理。

    1、右侧为成功的promise

    async function main() {
      let p = new Promise((resolve, reject) => {
        resolve('Ok')
      })
      let res = await p
      console.log(res)
    }
    
    main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    打印台显示:

    res结果为:Ok。

    2、右侧不是promise类型的值

    async function main() {
      let p = new Promise((resolve, reject) => {
        resolve('Ok')
      })
      let res = await 123
      console.log(res)
    }
    
    main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    打印台显示:

    res结果为:123。

    3、右侧的promise是失败状态

    async function main() {
      let p = new Promise((resolve, reject) => {
        reject('Error')
      })
      try {
        let res = await p
        } catch (error) {
          console.log(error)
        }
    }
    
    main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    打印台显示:

    Error。

    🌟async_await结合使用——fs读取文件

    普通回调函数读取文件操作:

    const fs = require('fs');
    fs.readFile('./resource/1.txt', (err, data1) => {
      if (err) throw err;
      fs.readFile('./resource/2.txt', (err, data2) => {
        if (err) throw err;
        console.log(data1 + data2)
      })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们可以看出,这一段代码运用了回调函数的嵌套,一旦读取的文件数量多的话就非常不利于阅读与维护。

    于是可以使用promise异步编程解决方法:

    const fs = require('fs');
    
    // promise封装读取文件函数
    const read = (path) => {
      return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
          if (err) reject(err);
          resolve(data.toString())
        })
      })
    }
    
    // 使用promise.then()方法读取文件
    read('./resource/1.txt').then(value => {
      console.log(value)
      return read('./resource/2.txt')
    }).then(value => {
      console.log(value)
    }).catch(reason => {
      console.warn(reason)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用了promise之后,我们可以用then方法的链式调用,调用读取的文件并将读取结果打印出来。

    但是依旧不够简洁,最终的解决方案是使用async_await结合:

    const fs = require('fs');
    // async与await方式实现
    const util = require('util')
    // util.promisify转为promise类型的函数
    const mineReadFile = util.promisify(fs.readFile)
    async function main() {
      try {
        // 读取文件内容
        let data1 = await mineReadFile('./resource/1.txt')
        let data2 = await mineReadFile('./resource/2.txt')
        // 其实这里await读取文件依旧是异步的,只不过看上去像同步
        console.log(data1 + data2)
      } catch (error) {
        console.log(error)
      }
    }
    main();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    util.promisify()方法将API转为promise类型的函数

    这里的两行await代码看上去是同步代码,其实其内部依旧是异步读取文件,只不过看上去像是同步的。

    🌟async_await结合使用——发送ajax请求

    promise.then.catch方法发送ajax请求:

    <body>
      <button id="btn">点击发送ajax请求</button>
      <script>
        function sendAJAX(url) {
          return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            xhr.open('GET', url)
            xhr.send()
            xhr.onreadystatechange = function () {
              if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                  resolve(xhr.response)
                } else {
                  reject(xhr.status)
                }
              }
            }
          })
        }
    
        const btn = document.getElementById('btn')
    		// promise.then.catch写法
        btn.addEventListener('click', function () {
          sendAJAX('http://127.0.0.1:8000/server')
            .then(value => {
              console.log(value)
            })
            .catch(reason => {
              console.log(reason)
            })
        })
      </script>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    async_await写法发送ajax请求:

    <body>
      <button id="btn">点击发送ajax请求</button>
      <script>
        function sendAJAX(url) {
          return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            xhr.open('GET', url)
            xhr.send()
            xhr.onreadystatechange = function () {
              if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                  resolve(xhr.response)
                } else {
                  reject(xhr.status)
                }
              }
            }
          })
        }
    
        const btn = document.getElementById('btn')
        // async_await写法
        btn.addEventListener('click', async function () {
          try {
            let result = await sendAJAX('http://127.0.0.1:8000/server')
            console.log(result)
          } catch (error) {
            console.log(error)
          }
        })
      </script>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    接收ajax请求的服务器:

    server.js

    const express = require('express')
    
    const app = express()
    
    app.all('/server', (request, response) => {
      response.setHeader('Access-Control-Allow-Origin', '*')
      response.setHeader('Access-Control-Allow-Headers', '*')
      response.setHeader('Access-Control-Allow-Methods', '*')
      response.send('codeMak1r.')
    })
    
    app.listen(8000, () => {
      console.log('服务已经监听到8000端口...')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🎉🎉如果觉得博主的文章还不错的话
    ➕关注博主👍点赞文章📁收藏文章
    ✏️原创不易你的支持将会是我最大的动力💪
    🧸感谢观看

  • 相关阅读:
    vue中sync修饰符
    综合实验——高级网络应用检测
    TK爆品剖析 水晶首饰降临节日历持续火爆TikTok,独立站卖到断货
    数据结构之顺序表
    Nginx文件跨域解决方案
    计算机毕业设计(附源码)python张家口市小学教育交流网站
    基于Java Web的传智播客crm企业管理系统的设计与实现
    22071.11.28
    计算机毕设 SpringBoot+Vue幼儿园管理系统 幼儿园信息管理系统 智慧幼儿园管理系统Java Vue MySQL数据库 远程调试 代码讲解
    管理人员应具备的基本素质
  • 原文地址:https://blog.csdn.net/Svik_zy/article/details/125443099