前端开发:Async/Await的使用心得

更新日期: 2021-07-20阅读: 1.1k标签: async
前端处理异步回调操作用到的方法之一:Async/Await。可以说Async/Await是Promise的升级版,而且应用了Async/Await的异步请求的情况下,可以让代码看起来像同步方式调用解决异步回调。

在ES7之前,了解到Promise是ES6为了解决异步回调而产生的解决方案,避免出现回调地狱(Callback Hell),那么ES7为什么又提出了新的Async/Await标准?问题答案就是:Promise虽然解决了异步嵌套的怪圈,使用表达清晰的链式表达;但是如果在实际开发过程中有些地方有大量的异步请求的时候,而且流程复杂嵌套的情况下,检查相关代码会发现一个比较尴尬。

一、Async/Await是什么?

Async/Await是基于Promise而来的,Async/Await是相互依存的,缺一不可,它们的出现就是为了Promise而来,也算是Promise的进化改良版,为的就是解决文章开始说的如果出现大量复杂嵌套不易读的Promise异步问题。

1、Async/Await基本含义

①Async/Await是基于Promise实现的,是写异步代码的新方式,它们不能用于普通的回调函数
②Async/Await也是非阻塞的;
③Async/Await的写法使得异步代码看起来像同步代码,简洁、便于读取。

2、Async/Await的语法

async必须声明的是一个function函数,await就必须是在async声明的函数内部使用,这是一个固定搭配,任何一种不符合这两个条件,程序就会报错,具体举实例来直观看一下:

let data = 'data'
a = async function () {
    const b = function () {
        await data
    }
}

二、Async/Awaitd的本质

1、 Async的本质

async是对generator的再一次语法糖封装,帮助实现了生成器的调用,使语句更贴近同步代码的表达方式,可以将async函数看做是多个异步操作封装的 promise对象。

async声明的函数的返回其实就是一个Promise,也就是说只要声明的函数是async,不管内部怎么处理,它返回的一定是一个Promise,举个例子如下所示:

(async function () {
    return 'Promis+++‘
})() // 返回的是Promise+++

2、 Awaitd的本质

await的本质其实是可以提供等同于“同步效果”的等待异步返回能力的语法糖,也就是then的语法糖。如果想使用await来执行一个异步操作,那么其调用函数必须使用async来声明。

await能返回一个Promise对象,也能返回一个值。若await返回的是Promise对象,那么还可以继续给await的返回值使用then函数。举个实例看一下:

const a = async ()=>{
    let message = '声明值111’
    let result = await message;
    console.log('由于上面的程序还没执行完,“等待一会”');
    return result
}
a().then(result=>{
  console.log('输出',result);
})

三、 Async/Await的优势

为什么说Async/Awaitd比Promise更胜一筹?具体原因如下所示。

1、 简洁明了

根据上述关于Async/Awaitd的实例可以看到,Async/Awaitd的写法很简单,相比Promise的写法,不用写.then,不用写匿名函数处理Promise的resolve值,也不用定义多余的data变量,更避免了嵌套代码的操作,大大省去了很多代码行,使得处理异步操作的代码简洁明了,方便查阅和精准定位。

2、 错误处理的方式

Async/Await可以让try/catch同时处理同步和异步的错误,而且在Promise中try/catch不能处理JSON.parse的错误,在Promise中需要使用.catch,但是错误处理的那坨代码会非常冗余,要知道实际开发过程中代码会比理论上的情况会更复杂。

通过使用Async/Await,try/catch能处理JSON.parse的错误,具体实例如下所示:

 const request = async () => {
        try {
            const data = JSON.parse(await getJSON())
            console.log(data)
        } catch (err) {
            console.log(err)
        }
 }

3、 条件语句

通过使用Async/Await,可以使得条件语句写法简洁又可以提高代码可读性,这里就不再举对比的例子,只举一个Async/Await的使用实例来说:

const request = async () => {
  const data = await getJSON()
  if (data.anotherRequest) {
    const moreData = await anotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

4、 中间值

在实际开发过程中会遇到这种场景:调用promise1,使用promise1返回的结果再去调用promise2,然后使用两者的结果去调用promise3。在没有使用Async/Await之前的写法,应该是这样的:

const request = () => {
     eturn promise1()
          .then(value1 => {
         return promise2(value1)
        .then(value2 => {        
               return promise3(value1, value2)
        })
    })
}

使用了Async/Await的写法之后,是这样的:


const request = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

通过上述两个写法,直观的看出来使用Async/Await之后会使得代码变得非常整洁简单,直观,高可读性。

5、 错误栈对比

如果实例中调用多个Promise,其中的一个Promise出现错误,Promise链中返回的错误栈没有显示具体的错误发生的位置信息,这就造成排查错误的耗时时长和解决的难度,甚至会起到反作用,假设错误栈的唯一函数名为errorPromise,但是它和错误没有直接关系。如果使用了Async/Await之后,错误栈会直接指向错误所在的函数,这样更清晰直观的方便排查问题所在,尤其是在查看分析错误日志的时候非常有效有用。

6、 调试

通过上面描述的Async/Await优点中,一直在反复强调Async/Await会使得代码简洁明了,其实在调试过程中,Async/Await也可以使得代码调试起来很轻松简单,相对于Promise来讲,不用再写太多箭头函数,可以直接像调试同步代码一样单步走,跳过await语句。

7、 中断/终止程序

首先要明确知道,Promise自身是不能终止的,Promise本身只是一个状态机,存储了三种状态,一旦进行发出请求,就必须要闭环,无法进行取消操作,就算是在前面讲到的pending状态,也只是一个挂起请求的状态,但不是取消。

但是使用Async/Await的时候,想要终止程序就很简单,那是因为Async/Await语义化很明显,和一般的function的写法类似,想要终端程序的时候,直接return一个值(“”、null、false等)就可以了,实际上就是直接返回一个Promise。具体实例如下所示:

let count = 3;
const a = async ()=>{
  const result = await delay(2000);
  const result1 = await delaySecond(count);
  if (count > 2) {
      return '';
    // return false;
    // return null;
  }
  console.log(await delay(2000));
  console.log(‘结束’);
};
a().then(result=>{
  console.log(result);
})
.catch(err=>{
  console.log(err);
})

async函数本质就是返回一个Promise。

四、实际开发过程中异步操作需要注意的事项

Async/Await使用for循环获取数据(串行)

根据上面Promise的for循环获取数据来做对比,直接使用上述实例的场景,来看看Async/Await的写法,具体操作如下所示:

(async ()=>{
    array = [timeout(2000), timeout(1000), timeout(1000)]
    for (var i=0; i < array.length; i++) {
        result = await array[i]();
        console.log(result);
    }
})()

通过对比,在这里还要夸一下Async/Await,直观的可以看到同样的需求,使用Async/Await来实现是不是非常的方便和简洁。

链接: https://www.fly63.com/article/detial/10555

JS中的async/await的执行顺序详解

虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript 的 async/await

ES6新特性Async

Async实际上是一个封装了自动化执行并返回一个Promise的Generator函数的语法糖。这句话的意思我们可以分为三个部分来解读:首先它有一个自动化执行,Generator函数是依靠不停的调用.net来依次执行的,Async有一个自动化执行的过程

Node.js Async 函数最佳实践

Node.js7.6起, Node.js 搭载了有async函数功能的V8引擎。当Node.js 8于10月31日成为LTS版本后,我们没有理由不使用async函数。接下来,我将简要介绍async函数,以及如何改变我们编写Node.js应用程序的方式。

将async/await编译到 ES3/ES5 (外部帮助库)

自2015年11 发布1.7版以来,TypeScript 已支持 async/await 关键字。编译器使用 yield 将异步函数转换为生成器函数。这意味着咱们无法针对 ES3 或 ES5,因为生成器仅在 ES6 中引入的。

你可能忽略的 async/await 问题

async/await 大家肯定都用过,在处理异步操作的时候真的是很方便。那今天主要讲一些在使用 async/await 时容易忽略和犯错的地方。上面的代码中,每一行都会 等待上一行的结果返回后才会执行。

使用async await通过for循环在图片onload加载成功后获取成功的图片地址

有一个图片列表,我想要在图片onload成功之后获取加载成功的图片列表,图片资源加载为异步,我们使用ES7的async await方式实现,多张图片,是用for循环。

ES8 Async 和 Await

Async 和 Awaiit 是 Promise 的扩展,我们知道 JavaScript 是单线程的,使用 Promise 之后可以使异步操作的书写更简洁,而 Async 使 Promise 像同步操作

有了 Promise 和 then,为什么还要使用 async?

最近代码写着写着,我突然意识到一个问题——我们既然已经有了 Promise 和 then,为啥还需要 async 和 await?这不是脱裤子放屁吗?

手写async await的最简实现

如果让你手写async函数的实现,你是不是会觉得很复杂?这篇文章带你用20行搞定它的核心。经常有人说async函数是generator函数的语法糖,那么到底是怎么样一个糖呢?让我们来一层层的剥开它的糖衣。

认识async/await

async/await是ES7的写法,可以让非同步call back写法看起来像同步的顺序去执行。以下我们new一个Promise的class并return给一个function

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!