async、await

本文深入讲解了async/await语法在JavaScript中的应用,包括其特点、优势及如何处理异步操作,通过具体案例展示了如何在Vue项目中使用async/await简化异步流程。

词法定义


  • async

    async 是“异步”的简写, async 用于申明一个异步的 function

  • await

    await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成。

借检https://www.cnblogs.com/airen123/p/9543490.html

特点:

  1. asayc的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数
  2. 异步async函数调用,跟普通函数的使用方式一样
  3. 异步async函数返回一个promise对象
  4. async函数配合await关键字使用(阻塞代码往下执行)
    是异步方法,但是阻塞式的

案例

模拟出一个摇色子的异步操作,先通过一个方法三秒之后拿到一个筛子数,第二步进行输出

//基本用法的async函数
let asyncFun = async function(){
    return 1
}
console.log(asyncFun())
//会返回一个promise对象


//使用场景
//摇色子方法
function dice(){
    return new Promise((resolve,reject)=>{
        let sino = parseInt(Math.random()*6+1)  //生成一个1~6之间的随机小数
        setTimeout(()=>{
            resolve(sino)
        },2000)
    })
}
//异步方法
 async function text(){
     let n= await dice()
      //await 关键字后面调用摇色子方法执行完毕之后,才进行变量赋值
     console.log("摇出来"+n)  //最后打印出摇出来的数
 }
text()

async/await的优点


  1. 方便级联调用:即调用依次发生的场景;

  2. 同步代码编写方式: Promise使用then函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;

  3. 多个参数传递: Promise的then函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await没有这个限制,可以当做普通的局部变量来处理,用let或者const定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作;

  4. 同步代码和异步代码可以一起编写: 使用Promise的时候最好将同步代码和异步代码放在不同的then节点中,这样结构更加清晰;async/await整个书写习惯都是同步的,不需要纠结同步和异步的区别,当然,异步过程需要包装成一个Promise对象放在await关键字后面;

  5. sync/await是对Promise的优化: async/await是基于Promise的,是进一步的一种优化,不过在写代码时,Promise本身的API出现得很少,很接近同步代码的写法;

使用场景

async主要来处理异步的操作,
需求:执行第一步,将执行第一步的结果返回给第二步使用。在ajax中先拿到一个接口的返回数据,后使用第一部返回的数据执行第二步操作的接口调用,达到异步操作。

Vue项目案例


普通案例promise:

methods: {
     getLocation(phoneNum) {
         return axios.post('/one接口', {
             phoneNum
         })
     },    
     getFaceList(province, city) {
         return axios.post('/two接口', {
             province,
             city
         })
     },  
     getFaceResult () {
          this.getLocation(this.phoneNum).then(res => {
              if (res.status === 200 && res.data.success) {
              let province = res.data.obj.province;
              let city = res.data.obj.city;
                  this.getFaceList(province, city).then(res => {
                        if(res.status === 200 && res.data.success) {
                             this.faceList = res.data.obj
                        }
                  })
              }
         }).catch(err => {
             console.log(err)
         })     
     }
}

这时你看到了then 的链式写法,有一点回调地域的感觉。现在我们在有async/ await 来改造一下。

async/ await案例:

首先把 getFaceResult 转化成一个async 函数,就是在其前面加async, 因为它的调用方法和普通函数的调用方法是一致,所以没有什么问题。然后就把 getLocation 和getFaceList 放到await 后面,等待执行, getFaceResult 函数修改如下:

async getFaceResult () {
                let location = await this.getLocation(this.phoneNum);
                if (location.data.success) {
                    let province = location.data.obj.province;
                    let city = location.data.obj.city;
                    let result = await this.getFaceList(province, city);
                    if (result.data.success) {
                        this.faceList = result.data.obj;
                    }
                }
            }

现在代码的书写方式,就像写同步代码一样,没有回调的感觉,非常舒服。

现在就还差一点需要说明,那就是怎么处理异常,如果请求发生异常,怎么处理? 它用的是try/catch 来捕获异常,把await 放到 try 中进行执行,如有异常,就使用catch 进行处理。

async getFaceResult () {
                try {
                    let location = await this.getLocation(this.phoneNum);
                    if (location.data.success) {
                        let province = location.data.obj.province;
                        let city = location.data.obj.city;
                        let result = await this.getFaceList(province, city);
                        if (result.data.success) {
                            this.faceList = result.data.obj;
                        }
                    }
                } catch(err) {
                    console.log(err);
                }
            }

Vue项目案例(封装)

http.js


'use strict'
 
import axios from 'axios'
import qs from 'qs'
 
axios.interceptors.request.use(config => {
  // loading
  return config
}, error => {
  return Promise.reject(error)
})
 
axios.interceptors.response.use(response => {
  return response
}, error => {
  return Promise.resolve(error.response)
})
 
function checkStatus (response) {
  // loading
  // 如果http状态码正常,则直接返回数据
  if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {
    return response
    // 如果不需要除了data之外的数据,可以直接 return response.data
  }
  // 异常状态下,把错误信息返回去
  return {
    status: -404,
    msg: '网络异常'
  }
}
 
function checkCode (res) {
  // 如果code异常(这里已经包括网络错误,服务器错误,后端抛出的错误),可以弹出一个错误提示,告诉用户
  if (res.status === -404) {
    alert(res.msg)
  }
  if (res.data && (!res.data.success)) {
    alert(res.data.error_msg)
  }
  return res
}
 
export default {
  post (data,url) {
    return axios({
      method: 'post',
      url: url,
      data: qs.stringify(data),
      timeout: 10000,
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      }
    }).then(
      (response) => {
        return checkStatus(response)
      }
    )
  },
  get (url, params) {
    return axios({
      method: 'get',
      baseURL: 'https://cnodejs.org/api/v1',
      url,
      params, // get 请求时带的参数
      timeout: 10000,
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(
      (response) => {
        return checkStatus(response)
      }
    ).then(
      (res) => {
        return checkCode(res)
      }
    )
  }
}

api.js

export default {
  getCode: 'http://127.0.0.1:8888/.....'
}

auth.vue

import http from '../../utils/http'
import api from '../../utils/api'
 
   methods: {
      fetchData: async function () {
        var that = this
        var code = Store.fetchYqm();
        let params = {
          inviteCode: code
        }
        const response = await http.post(params,api.getCode)
         var resJson = response.data;
        
      }
}

公司的项目案例
在这里插入图片描述
在这里插入图片描述

<think>首先,用户的问题是:“我想Understanding and using async/await in programming 请问Introduction to async await in programming and its usage”。这翻译成中文是“我想了解编程中的async/await,请问async/await在编程中的介绍及其使用”。 系统级指令要求: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 用户可见层要求: - 回答结构清晰,帮助用户逐步解决问题。 参考站内引用: - 引用[1]: 关于Async/Await的性能成本。 - 引用[2]: 关于回退机制的简要介绍。 我需要基于这些引用构建回答。用户的问题是关于async/await的介绍和使用,所以我应该聚焦在编程中的async/await概念,尤其是在C#或类似语言中,因为引用[1]提到了C#编译器。 回答结构: 1. **介绍async/await的概念**:解释什么是async/await,为什么需要它。 2. **基本用法**:展示代码示例。 3. **优点和缺点**:讨论其好处和潜在问题。 4. **引用相关部分**:自然地整合引用[1]和[^2]。 5. **生成相关问题**:在回答结束时添加相关问题部分。 确保使用中文回答。 步骤: - **介绍**:定义async/await。例如,async/await是一种用于处理异步操作的模式,避免阻塞主线程。 - **用法**:提供简单的代码示例。引用[1]中有一个C#示例,我可以基于它。 - **性能方面**:引用[1]讨论了性能成本,所以我应该提到这一点。 - **回退机制**:引用[^2]是关于回退机制的,可能用于错误处理,所以我可以在讨论错误处理时提及。 - **数学表达式**:用户问题中没有明显的数学内容,但如果有相关概念(如时间复杂性),我可以使用LaTeX。例如,在讨论性能时,如果有公式,使用$...$或$$...$$。 - 例如,如果提到时间复杂度,可以写成$O(n)$。 - **生成相关问题**:在回答末尾添加“相关问题”部分。 生成相关问题: - 基于主题,例如: 1. async/await在哪些语言中可用? 2. 如何处理async代码中的错误? 3. async/await的性能优化技巧? 4. 与Promise或其他异步模式的比较? 5. 实际应用场景? 引用标识: - 在回答中,当引用[1]的内容时,添加[^1]。 - 引用[2]添加[^2]。 最终回答结构: 1. 标题或引言:介绍主题。 2. 主体:分步骤解释。 3. 代码块:展示示例。 4. 讨论:包括优点、缺点、性能。 5. 相关问题部分。 现在,构建内容: - **引言**:Async/await是一种编程模式,用于简化异步代码的编写,避免回调地狱,提高可读性。 - **基本概念**:在C#中,async关键字修饰方法,await关键字用于等待异步操作完成。 - **代码示例**:使用引用[1]中的例子,但确保语法正确。 - 原引用代码:public static async Task<int> SumAsync(Task<int> a, Task<int> b, Task<int> c) { return Sum(await a, await b, await c); } - 我需要用中文解释。 - **性能**:提到async/await有性能成本,因为涉及状态机生成[^1]。 - **错误处理**:提到回退机制用于处理失败操作[^2]。 - **LaTeX**:如果没有直接数学,但假设在讨论时间,可以添加。例如,异步操作的延迟可能用$t$表示。 - 为了符合指令,我可以添加一个简单的公式,比如在讨论性能时,提到时间复杂度为$O(1)$或类似,但实际中可能不必要。指令说“如果包括”,所以如果没有,就不强制。 - **结束**:总结,并添加相关问题。 相关问题: 1. async/await如何影响应用程序的性能? 2. 在异步编程中如何处理异常? 3. async/await与其他异步模式(如Promise)有什么区别? 4. 在实际项目中,async/await的常见陷阱是什么? 5. 如何优化async/await代码以减少开销? 确保回答真实可靠:基于一般知识,引用提供的参考。</think>### Async/Await在编程中的介绍及其使用 Async/await是一种现代编程模式,用于简化异步操作的处理,避免传统的回调地狱(Callback Hell),提高代码的可读性和可维护性。它广泛应用于C#、JavaScript、Python等语言中,允许开发者以同步的方式编写异步代码。核心思想是:使用`async`关键字标记异步方法,`await`关键字等待异步操作完成,而不会阻塞主线程。这在处理I/O密集型任务(如网络请求、文件读写)时尤其重要,因为它能释放系统资源,提升应用程序的响应性和吞吐量。 #### 1. **基本概念与工作原理** - **async关键字**:用于修饰方法,表明该方法包含异步操作。被修饰的方法返回一个`Task`(在C#中)或`Promise`(在JavaScript中),表示异步操作的结果。 - **await关键字**:用于等待异步操作完成。它会暂停当前方法的执行,直到异步操作返回结果,但不会阻塞线程,允许其他任务继续运行。 - **优势**:与传统回调或线程相比,async/await代码更易读、更少嵌套。例如,它避免了多层回调的复杂性,使错误处理更直观。 - **数学表示**:在性能分析中,async/await的开销可建模为状态机生成的成本。假设异步操作的平均延迟为$t$毫秒,使用async/await后,总等待时间可近似为$T = n \times t$(其中$n$是操作数),但实际中因上下文切换和调度而略有增加[^1]。 #### 2. **基本用法与代码示例** 以下以C#语言为例,展示async/await的典型用法。C#编译器支持在几乎所有表达式中使用`await`,包括作为更大表达式的一部分,这提高了灵活性[^1]。 ```csharp // 定义一个异步方法,计算三个任务结果的和 public static async Task<int> SumAsync(Task<int> a, Task<int> b, Task<int> c) { // 使用await等待每个任务完成,并获取结果 int resultA = await a; int resultB = await b; int resultC = await c; return Sum(resultA, resultB, resultC); // 调用同步辅助方法 } private static int Sum(int a, int b, int c) { return a + b + c; // 简单的同步计算 } ``` **解释**: - `SumAsync`方法被标记为`async`,返回`Task<int>`。 - `await a`、`await b`、`await c`会依次等待每个任务完成,但执行是非阻塞的:如果某个任务未完成,控制权会返回给调用方,允许其他代码运行。 - 在JavaScript或Python中,语法类似,但关键字和返回类型略有不同(如JavaScript使用`async/await`与`Promise`)。 这个示例展示了async/await如何简化异步代码:它看起来像同步代码,但内部是异步执行的。实际应用中,这常用于数据库查询或API调用。 #### 3. **优点与潜在问题** - **优点**: - **可读性高**:代码结构清晰,减少嵌套。 - **资源高效**:避免线程阻塞,提升并发性能,特别适合I/O密集型应用。 - **错误处理简化**:可使用`try/catch`块捕获异常,与同步代码一致。 - **缺点与注意事项**: - **性能开销**:async/await涉及状态机生成和上下文切换,可能引入额外成本。在C#中,编译器会为每个`async`方法生成一个状态机,增加内存和CPU使用[^1]。对于高性能场景,需谨慎使用。 - **死锁风险**:如果在UI线程或同步上下文中错误使用`await`,可能导致死锁。解决方案是使用`ConfigureAwait(false)`避免上下文捕获。 - **错误处理扩展**:对于可能失败的操作,应结合回退机制(如指数退避),以重试失败的任务[^2]。例如,网络请求失败时,自动重试并逐步增加延迟。 #### 4. **实际应用场景** - **Web开发**:在ASP.NET Core中处理HTTP请求时,使用async/await异步访问数据库,提升服务器吞吐量。 - **移动应用**:在Android或iOS开发中,异步加载网络数据,防止UI冻结。 - **桌面应用**:在WPF或WinForms中,后台执行耗时操作,保持界面响应。 - **云服务**:Azure Functions或AWS Lambda中,处理事件驱动的异步任务。 总之,async/await是现代异步编程的核心工具,它通过简化代码结构显著提升开发效率。但需注意性能开销和正确使用模式,以避免常见陷阱[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

star@田兴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值