Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面一起来看看这篇文章:Async/Await替代Promise的6个理由。

什么是Async/Await?

  • async/await是写异步代码的新方式,以前的方法有回调函数和Promise。
  • async/await是基于Promise实现的,它不能用于普通的回调函数。
  • async/await与Promise一样,是非阻塞的。
  • async/await使得异步代码看起来像同步代码,这正是它的魔力所在。

      Async/Await语法

      示例中,getJSON函数返回一个promise,这个promise成功resolve时会返回一个JSON对象。我们只是调用这个函数,打印返回的JSON对象,然后返回”done”。

  •   使用Promise是这样的:
    const makeRequest = () =>
    getJSON()
    .then(data => {
    console.log(data)
    return "done"
    }) makeRequest()

      使用Async/Await是这样的:

    const makeRequest = async () => {
    console.log(await getJSON())
    return "done"
    } makeRequest()

      它们有一些细微不同:

    • 函数前面多了一个aync关键字。await关键字只能用在aync定义的函数内。async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串”done”)
    • 第1点暗示我们不能在最外层代码中使用await,因为不在async函数内。
      // 不能在最外层代码中使用await
      await makeRequest() // 这是会出事情的
      makeRequest().then((result) => {
      // 代码
      })
    • await getJSON()表示console.log会等到getJSON的promise成功reosolve之后再执行。
    • 为什么Async/Await更好?

      1. 简洁

      由示例可知,使用Async/Await明显节约了不少代码。我们不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。这些小的优点会迅速累计起来,这在之后的代码示例中会更加明显。

      2. 错误处理

      Async/Await让try/catch可以同时处理同步和异步错误。在下面的promise示例中,try/catch不能处理JSON.parse的错误,因为它在Promise中。我们需要使用.catch,这样错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂。

      const makeRequest = () => {
      try {
      getJSON()
      .then(result => {
      // JSON.parse可能会出错
      const data = JSON.parse(result)
      console.log(data)
      })
      // 取消注释,处理异步代码的错误
      // .catch((err) => {
      // console.log(err)
      // })
      } catch (err) {
      console.log(err)
      }
      }

        使用aync/await的话,catch能处理JSON.parse错误:

      const makeRequest = async () => {
      try {
      // this parse may fail
      const data = JSON.parse(await getJSON())
      console.log(data)
      } catch (err) {
      console.log(err)
      }
      }

        

      3. 条件语句

      下面示例中,需要获取数据,然后根据返回数据决定是直接返回,还是继续获取更多的数据。

      const makeRequest = () => {
      return getJSON()
      .then(data => {
      if (data.needsAnotherRequest) {
      return makeAnotherRequest(data)
      .then(moreData => {
      console.log(moreData)
      return moreData
      })
      } else {
      console.log(data)
      return data
      }
      })
      }

        上面的代码使用async/await编写可以大大地提高可读性:

      const makeRequest = async () => {
      const data = await getJSON()
      if (data.needsAnotherRequest) {
      const moreData = await makeAnotherRequest(data);
      console.log(moreData)
      return moreData
      } else {
      console.log(data)
      return data
      }
      }

        

      4. 中间值

      你很可能遇到过这样的场景,调用promise1,使用promise1返回的结果去调用promise2,然后使用两者的结果去调用promise3。你的代码很可能是这样的:

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

        如果promise3不需要value1,可以很简单地将promise嵌套铺平。如果你忍受不了嵌套,你可以将value 1 & 2 放进Promise.all来避免深层嵌套:

      const makeRequest = () => {
      return promise1()
      .then(value1 => {
      return Promise.all([value1, promise2(value1)])
      })
      .then(([value1, value2]) => {
      return promise3(value1, value2)
      })
      }

        这种方法为了可读性牺牲了语义。除了避免嵌套,并没有其他理由将value1和value2放在一个数组中。

      使用async/await的话,代码会变得异常简单和直观。

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

        

      5. 错误栈

    • 下面示例中调用了多个Promise,假设Promise链中某个地方抛出了一个错误:
      const makeRequest = () => {
      return callAPromise()
      .then(() => callAPromise())
      .then(() => callAPromise())
      .then(() => callAPromise())
      .then(() => callAPromise())
      .then(() => {
      throw new Error("oops");
      })
      } makeRequest()
      .catch(err => {
      console.log(err);
      // output
      // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
      })

        Promise链中返回的错误栈没有给出错误发生位置的线索。更糟糕的是,它会误导我们;错误栈中唯一的函数名为callAPromise,然而它和错误没有关系。(文件名和行号还是有用的)。

      然而,async/await中的错误栈会指向错误所在的函数:

      const makeRequest = async () => {
      await callAPromise()
      await callAPromise()
      await callAPromise()
      await callAPromise()
      await callAPromise()
      throw new Error("oops");
      } makeRequest()
      .catch(err => {
      console.log(err);
      // output
      // Error: oops at makeRequest (index.js:7:9)
      })

        在开发环境中,这一点优势并不大。但是,当你分析生产环境的错误日志时,它将非常有用。这时,知道错误发生在makeRequest比知道错误发生在then链中要好

Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面一起来看看这篇文章:Async/Await替代Promise的6个理由。

什么是Async/Await?

  • async/await是写异步代码的新方式,以前的方法有回调函数和Promise。
  • async/await是基于Promise实现的,它不能用于普通的回调函数。
  • async/await与Promise一样,是非阻塞的。
  • async/await使得异步代码看起来像同步代码,这正是它的魔力所在。

Async/Await语法

示例中,getJSON函数返回一个promise,这个promise成功resolve时会返回一个JSON对象。我们只是调用这个函数,打印返回的JSON对象,然后返回”done”。

使用Promiconst makeRequest =()=>

  getJSON()
.then(data=> {
console.log(data)
return "done"
})它们有一些细微不同:
  • 函数前面多了一个aync关键字。await关键字只能用在aync定义的函数内。async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串”done”)
  • 第1点暗示我们不能在最外层代码中使用await,因为不在async函数内。
// 不能在最外层代码中使用await
await makeRequest() // 这是会出事情的
makeRequest().then((result)=>{//

await getJSON()表示console.log会等到getJSON的promise成功reosolve之后再执行。

为什么Async/Await更好?

1. 简洁

由示例可知,使用Async/Await明显节约了不少代码。我们不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。这些小的优点会迅速累计起来,这在之后的代码示例中会更加明显。

2. 错误处理

Async/Await让try/catch可以同时处理同步和异步错误。在下面的promise示例中,try/catch不能处理JSON.parse的错误,因为它在Promise中。我们需要使用.catch,这样错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂。

const makeRequest =()=> {
try {
getJSON()
.then(result=> {
// JSON.parse可能会出错
const data = JSON.parse(result)
console.log(data)
})
// 取消注释,处理异步代码的错误
// .catch((err) => {// console.log(err)// })}catch(err){
consol

使用aync/await的话,catch能处理JSON.parse错误:

const makeRequest = async ()=> {
try {
// this parse may fail
const data = JSON.parse(await getJSON())
console.log(data)
} catch (err) {
console.lo

3. 条件语句

下面示例中,需要获取数据,然后根据返回数据决定是直接返回,还是继续获取更多const makeRequest =()=>{

  return getJSON()
.then(data=> {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData=> {
console.log(moreData)
return moreData
})
} else {
console.log(data)
5

在开发环境中,这一点优势并不大。但是,当你分析生产环境的错误日志时,它将非常有用。这时,知道错误发生在makeRequest比知道错误发生在then链中要好。

6. 调试

最后一点,也是非常重要的一点在于,async/await能够使得代码调试更简单。2个理由使得调试Promise变得非常痛苦:

  • 不能在返回表达式的箭头函数中设置断点 
  • 如果你在.then代码块中设置断点,使用Step Over快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。

使用await/async时,你不再需要那么多箭头函数,这样你就可以像调试同步代码一样跳过await语句。

结论

Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。

忧虑

对于Async/Await,也许你有一些合理的怀疑:

  • 它使得异步代码不在明显: 我们已经习惯了用回调函数或者.then来识别异步代码,我们可能需要花数个星期去习惯新的标志。但是,C#拥有这个特性已经很多年了,熟悉它的朋友应该知道暂时的稍微不方便是值得的。
  • Node 7不是LTS(长期支持版本): 但是,Node 8下个月就会发布,将代码迁移到新版本会非常简单。

参考:https://cnodejs.org/topic/58e4914e43ee7e7106c13541

js异步回调Async/Await与Promise区别 新学习使用Async/Await的更多相关文章

  1. C“中断” 与 JS“异步回调” 横向对比

    在底层C语言中,有一个非常重要而特别的概念,叫做“中断”.用比喻来说,我正在写着博客,突然我妈打个电话过来,我就离开了键盘去接电话了,然后写博客就中断了,我聊完电话回来再继续写.乍一听似乎并没有什么大 ...

  2. 深入浅出写一个多级异步回调从基础到Promise实现的Demo

    今天一时兴起,写了一个渐进升级的异步调用demo,记录一下. 1. 最基础的同步调用 //需求:f2在f1之后执行,且依赖f1的返回值.如下: function f1(){ var s="1 ...

  3. co.js异步回调原理理解

    co.js是基于es6的generator实现的,相当于generator函数的一个自动执行器 generator的简单介绍 function* fn(){ before() yield firstY ...

  4. js异步回调

    简单理解:js是单线程的,Ajax请求远程数据.IO等会很耗时,引起堵塞可能会引起反应时间太长页面失去反应. 回调:A函数作为一个参数传给B函数,执行完B后再执行A: 同步回调: function A ...

  5. 关于js 异步回调的一些方法

    http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

  6. 通知url必须为直接可访问的url,不能携带参数 异步接收微信支付结果通知的回调地址 不能携带参数。 回调地址后是否可以加自定义参数 同步回调地址 异步回调地址 return_url和notify_url的区别

    [微信支付]微信小程序支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7 通知url必须为直接可访问的 ...

  7. 支付回调地址 同步回调地址 异步回调地址 return_url和notify_url的区别

    [微信支付]JSAPI支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=10 退款结果通知 ...

  8. 浅析JS异步执行机制

    前言 JS异步执行机制具有非常重要的地位,尤其体现在回调函数和事件等方面.本文将针对JS异步执行机制进行一个简单的分析. 从一份代码讲起 下面是两个经典的JS定时执行函数,这两个函数的区别相信对JS有 ...

  9. JS异步编程 (2) - Promise、Generator、async/await

    JS异步编程 (2) - Promise.Generator.async/await 上篇文章我们讲了下JS异步编程的相关知识,比如什么是异步,为什么要使用异步编程以及在浏览器中JS如何实现异步的.最 ...

随机推荐

  1. GeoMesa Spark

    GeoMesa Spark 一.Spark JTS 1.1 示例 1.2配置 1.3 地理空间用户定义的类型和功能 1.4 geojson输出 1.5 Building 二.Spark Core 2. ...

  2. Django(ORM单表操作)

    默认使用sqllite数据库 修改为mysql数据库 创建数据库 在app models中编写创建数据库类 from django.db import models class Book(models ...

  3. RabbitMQ (简单集群部署操作)

    RabbitMQ 集群部署 前期准备 第一步:三台linux系统(centos7.3) 主机名(hostname) 网卡ip node1 192.168.137.138 node2 192.168.1 ...

  4. python--基础1(pip,虚拟环境、python编写规范)

    python简介 1.Python是一种解释型脚本语言; 2.Python在设计上坚持了清晰划一的风格,这使得Python成为一门易读.易维护,并且被大量用户所欢迎的.用途广泛的语言; 3.pytho ...

  5. maven高级笔记

    Maven高级 1.maven基础知识回顾 1.1 maven介绍 maven 是一个项目管理工具,主要作用是在项目开发阶段对Java项目进行依赖管理和项目构建. 依赖管理:就是对jar包的管理.通过 ...

  6. P3195 [HNOI2008] 玩具装箱(斜率优化DP)

    题目链接 设\(d[i]\)为将前 \(i\) 个玩具装入箱中所需得最小费用 容易得到动态转移方程: \[d[i] = min(d[j] + (s[i]-s[j]+i-j-1-L)^2), (j< ...

  7. 使用eclipse写第一个Java_web的hello_world项目

    1.先创建一个Java_web项目 如果你没有下载过Tomcat服务器,不会配置,建议看一下我得这一篇博客:https://www.cnblogs.com/kongbursi-2292702937/p ...

  8. 2020牛客暑期多校训练营(第二场)Fake Maxpooling

    传送门:Fake Maxpooling 题意:给出矩阵的行数n和列数m,矩阵 Aij = lcm( i , j )  ,求每个大小为k*k的子矩阵的最大值的和. 题解:如果暴力求解肯定会t,所以要智取 ...

  9. 六、Python集合定义和基本操作方法

    一.集合的定义方法及特点 1.特点: (1)由不同元素组成 #集合由不同元素构成 s={1,2,3,3,4,3,3,} print(s)#运行结果:{1, 2, 3, 4} (2)集合无序 #集合无序 ...

  10. java的两性

    java具有解释与编译两种特性 本来是昨天的,可以文件丢失了......(我没有偷懒哦,没有!) 所以凭记忆随便写了点 解释就像直接翻译一本书拿给别人看,编译就像找个翻译官一句句翻译给你t听 解释型( ...