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

前言

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

本文目录

  • 前言
  • async函数
  • await表达式
  • async_await结合使用——fs读取文件
  • async_await结合使用——发送ajax请求

坚持创作✏️,一起学习,码出未来‍!

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>

打印台显示:

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


<body>
  <script>
    async function main() {
      throw 'Oh NO!'
    }

    let result = main()
    console.log(result)
  script>
body>

打印台显示:

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()

打印台显示:

res结果为:Ok。

2、右侧不是promise类型的值

async function main() {
  let p = new Promise((resolve, reject) => {
    resolve('Ok')
  })
  let res = await 123
  console.log(res)
}

main()

打印台显示:

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()

打印台显示:

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)
  })
})

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

于是可以使用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)
})

使用了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();

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>

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>

接收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端口...')
})

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

你可能感兴趣的:(【前端基础】--克莱因,#,【Promise】--无量,JavaScript,javascript,async/await,promise)