ES6问答-async函数

async函数

  1. async是什么?它和Genernator函数外观上的区别是什么?

    const asyncReadFile = async function(){
        const f1 = await readFile(url1)
        const f2 = await readFile(url2)
    }

    async是Genernator函数的语法糖。

    asyncGenernator的区别有两点:

    • Genernator*变成async
    • yield变成 await
  2. asyncGenernator做了哪些改进?

    • 内置执行器。

      执行时和普通函数一样,只需要调用函数就完了,不需要 next()方法

    • 更好的语义。

      async表示它后面的函数里有异步操作;await表示紧跟在后面的表达式需要等待结果

    • 更广的适用性。

      await后面可以Genernator, Promise对象和原始类型的值。(原始类型的值会被自动转化为resolved状态的Promise对象)

    • 返回值是Promise

      async函数返回的是Promise对象,方便用 then进行下一步操作

    • 总的来说:async函数可看成多个异步操作,包装成一个Promise对象,而await命令就是内部then命令的语法糖。
  3. async执行的例子:

    function timeout(ms){
      return new Promise((resolve) => {
        setTimeout(resolve, ms)
      })
    }
    async function asyncPrint(value, ms){
      await timeout(ms);
      console.log(value)
    }
    
    asyncPrint("你好啊", 5000)

    5s之后打印 “你好啊”

    以上 asyncPrint的意思是,等待timeout函数执行完了之后,才会继续执行 console.log(value)

  4. async函数的几种使用场景?

    五种场景下:

    • 函数声明

      async function foo(){}
    • 函数表达式

      const foo = async function(){}
    • 箭头函数

      const foo = async () => {}
    • 对象的方法

      let obj = {
       async foo(){
      
           }
      }
      obj.foo().then(...)
    • class方法

      class Storage{
       constructor(){
              this.cachePromise = caches.open("avatars")
          }
          async getAvatar(name){
              const cache = await this.cachePromise;
              return cache.match()
          }
      }
      const storage  = new Storage()
      storage.getAvatar("joy").then(...)
  5. async函数返回什么?

    返回一个 Promise对象。

    async函数内部 return语句的返回值,会成为then方法回调函数的参数。

    async函数内部抛出的错误,会导致返回的Promise对象变为 rejected状态

  6. `async函数中Promise对象是如何变化的?

    async函数返回的是Promise对象P。必须等到内部 await命令的Promise对象执行完后,P才会发生状态改变,除非遇到return语句,或者抛出了错误。

    换言之,async函数 内部的异步操作执行完了,才会执行调用它时后面then方法指定的回调函数。

  7. await命令的返回值是什么?

    • 正常情况下,await后面是Promise对象,会返回此对象的结果;如果不是Promise对象,直接返回对应的值
    • await命令后面跟了 thenable对象,会把 thenable对象当做 Promise对象来处理
  8. await后面的Promise对象如果变为 rejected会怎样?

    • rejected的参数会被async函数catch方法的回调函数接收到。

      async function f() {
        await Promise.reject('出错了');
      }
      
      f()
      .then(v => console.log(v))
      .catch(e => console.log(e))
    • 任何一个await语句的Promise对象变为reject状态,整个async函数都会被中断

      async function f() {
        await Promise.reject('出错了');
        await Promise.resolve('hello world'); // 不会执行
      }
  9. 如果希望前一个异步操作失败,不中断后面的异步操作,怎么处理?

    两种方法:

    • 把第一个await放到 try...catch里面

      async function f(){
          try{
              await Promise.reject("出错了")
          }catch(e){}
          return await Promise.resolve("hello world")
      }
      f().then(v =>console.log(v)).catch(e => console.log(e))
      // 打印的是  hello world
    • await后面的Promise对象再跟一个 catch方法,处理前面可能出现的错误

      async function f(){
        await Promise.reject("出错啦").catch(e => {
          console.log("await 内部promise被reject了")
        })
        return await Promise.resolve("hello world");
      }
      f().then(v => console.log(v)).catch(e => console.log(e))

      打印的内容是:

      await 内部promise被reject了
      hello world

  10. await后面的异步操作出错了(例如某行代码throw 了一个Error),是什么意思?

    async函数返回的Promise对象被reject

    async function f() {
      await new Promise(function (resolve, reject) {
        throw new Error('出错了');
      });
    }
    
    f()
    .then(v => console.log(v))
    .catch(e => console.log(e)) // catch执行了, e就是抛出的错误对象 new Error('出错了')
  11. 如何防止出错呢?

    还是将其放到try{ }catch(e){ }代码块中。

    如果有多个await命令,可以将其统一放到try{ }catch(e){ }结构里。
    下面是实际例子: 多次发起客户端请求,如果请求成功,跳出循环往下执行;如果不成功,继续请求,直到达到最大数目 NUM_RETRIES

    async function test(){
      let i;
      for(i = 0; i < NUM_RETRIES; ++i){
        try{
          await superagent.get(url)
          break;
        }catch(err){}
      }
      console.log(i)
    }
    test()

    如果await操作成功,则会break,跳出for循环;如果await操作不成功,则会被catch住,然后继续下一轮for循环,直到超过 NUM_RETRIES或者 await操作成功。

  12. asyncawait有哪些使用上注意的点?

    • await命令后的Promise对象可能reject,因此await命令最好放在try{ }catch(e){ }代码块中

      async function myFunction() {
        try {
          await somethingThatReturnsAPromise();
        } catch (err) {
          console.log(err);
        }
      }
      
      // 另一种写法
      
      async function myFunction() {
        await somethingThatReturnsAPromise()
        .catch(function (err) {
          console.log(err);
        });
      }
    • 多个await异步操作时,如果不存在继发关系,让它们同时触发比较好

      可以结合 Promise.all方法

      // 写法一
      let [foo, bar] = await Promise.all([getFoo(), getBar()]);
      
      // 写法二
      let fooPromise = getFoo();
      let barPromise = getBar();
      let foo = await fooPromise;
      let bar = await barPromise;
    • await命令只能用在async函数中,用在普通函数里会报错

      注意forEach的回调函数,await也不能出现在回调函数里

    • async函数可以保留运行堆栈

      看例子:

      const a = () => {
          b().then(() => c()) ;
      }
      
      const a = async () => {
          await b();
          c();
      }

      上面的例子中,b运行时,a可能已经执行完了。如果此时b或c报错,错误堆栈将不包括a

      下面例子中,b运行时,a只是暂停,若此时b或者c报错了,错误堆栈中将包括a

  13. Promise写法和Genernator写法,async有什么好处?

    Promise写法有很多catchthen,语义性不强。

    Genernator函数需要有一个任务运行器,自动执行Genernator函数,并且 yield后面的表达式,必须返回Promise对象

    async最简洁,最符合语义,将Genernator写法的自动执行器,改在 语言层面提供,不暴露给用户,代码量最少。

    async function chainAnimationAsync(elem, ainmations){
        let ret = null
        try{
            for(letanim of animations){
                ret = await anim(elem);
            }
        }catch(e){}
        return ret
    }
  14. async的实例: 按顺序完成异步操作——依次远程读取一组URL,然后按照读取顺序输出结果

    async function logInOrder(urls){
      const textPromises = urls.map(async url => {
        const response = await fetch(url)
        return response.text()
      })
      for(const textPromise of textPromises){
        console.log(await textPromise)
      }
    }

    map的参数是async函数。这几个async是并发的。只有async函数内部才是继发的【const response = await fetch(url)return response.text() 先执行】,外部并不受影响。

    后面在 for...of循环内部使用了 await,这几个await是顺序执行。

Image placeholder
sinper
未设置
  73人点赞

没有讨论,发表一下自己的看法吧

推荐文章
CentOS7 下使用 rsync+sersync 配置文件自动同步

为什么需要文件自动同步功能? 我们平时上传代码,可以通过ftp、sftp等将文件上传至服务器,耗时耗力,而且很容易出错。如果服务器数量少还好,一但服务器数量增加,压力可想而知。 这个时候我们可以使用各

Rust 标准库中的 async/await (async-std)

Rust对齐标准库中的async/await(async-std)简介现在的rust生态中,async/await在rust1.39中已经stable,其他库还有futures已经到0.3.x,还有就

Linux 文件同步工具之 rsync

学习背景 1.最近公司的项目在使用jenkins做自动化构建,因为jenkins在构建时是比较耗性能的,便单独使用了一台服务器做构建服务器。但是个人觉得这样成本过高,单独拿一台服务器来构建并且该服务器

利用 consul+nginx-upsync 实现动态负载

如果Nginx遇到大流量和高负载,修改配置文件重启可能并不总是那么方便,因为恢复Nginx并重载配置会进一步增加系统负载,并很可能暂时降低性能。而一个个修改配置文件也是很容易出错和费时间的操作。 这时

利用 consul+nginx-upsync 实现动态负载

这是前一段时间学习的课程上面的,自己实际操作了一下,详细操作及说明如下。如果Nginx遇到大流量和高负载,修改配置文件重启可能并不总是那么方便,因为恢复Nginx并重载配置会进一步增加系统负载,并很可

死磕Synchronized底层实现,面试你还怕什么?

关于 synchronized 的底层实现,网上有很多文章了。但是很多文章要么作者根本没看代码,仅仅是根据网上其他文章总结、照搬而成,难免有些错误;要么很多点都是一笔带过,对于为什么这样实现没有一个说

深入了解JavaScript async/await !

Asyncfunctions让我们以async这个关键字开始。它可以被放置在任何函数前面,像下面这样:asyncfunctionf(){ return1; }在函数前面的「async」这个单词表达了一

ES6系列之箭头函数全解析

引言ES6中允许使用箭头=>来定义箭头函数,是ES6中较受欢迎也较常使用的新增特性。本文将从箭头函数的基本语法,与普通函数对比,箭头函数不适用场景三个方面进行梳理。基本语法//箭头函数 letfunc

Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR中直播页面和视频列表页面的区别介绍

背景分析随着平安城市、智慧城市、雪亮工程、智能交通等各项建设的持续开展,安防逐渐得到普及,面对如此广阔的市场,对安防企业来说不仅仅是机遇更多的是挑战。现今大多数摄像头一直没能摆脱人工监控的传统监控方式

Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR如何使用Excel将通道配置简单化?

进入移动互联网时代以来,企业微信公众号已成为除官网以外非常重要的宣传渠道,当3.2亿直播用户与9亿微信用户的势能累加,在微信上开启直播已成为越来越多企业的必然选择。EasyNVR核心在于摄像机的音视频

Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR登陆用户名密码失效问题解决方案

背景分析随着互联网基础设施建设的发展,4G/5G/NB-IoT各种网络技术的大规模商用,视频随时随地可看、可控的诉求越来越多,互联网思维、架构和技术引入进传统监控行业里,成为新形势下全终端监控的基础需

RTSP、RTMP网络摄像头互联网无插件直播视频流媒体服务器EasyNVR在windows上无法启动问题排查

背景需求随着雪亮工程、明厨亮灶、手机看店、智慧幼儿园监控等行业开始将传统的安防摄像头进行互联网、微信直播,我们知道摄像头直播的春天了。将安防摄像头或NVR上的视频流转成互联网直播常用的RTSP、RTM

安防摄像头网页无插件直播流媒体服务器EasyNVR在IE浏览器下的 pointer-events- none前端兼容性调试

背景说明由于互联网的飞速发展,传统安防摄像头的视频监控直播与互联网直播相结合是大势所趋。传统安防的直播大多在一个局域网内,在播放的客户端上也是有所限制,一般都需要OCXWeb插件进行直播。对于安防监控

RTSP-ONVIF协议安防视频监控流媒体服务解决方案EasyNVR在Windows重启时提示“进程意外终止”问题解析

什么是ONVIFOpenNetworkVideoInterfaceForum,开放型网络视频接口论坛,以公开、开放的原则共同制定开放性行业标准。是一个提供开放网络视频接口的论坛组织。ONVIF规范描述

安防摄像头RTSP/Onvif协议网页无插件直播视频流媒体服务器EasyNVR之按需直播如何有效利用最大上行带宽

介绍一般情况下,直播默认的播放方式是非按需直播,但很多情况下,不少用户会选择按需直播。按需直播能够减少带宽流量和服务器性能占用,最优的提高服务器的使用效率。下面我们来系统介绍下EasyNVR中按需直播

RTSP网络摄像头/海康大华硬盘录像机网页无插件直播方案EasyNVR如何实现RTMP/FLV/HLS/RTSP直播流分发

背景需求对于摄像机直播,客户反馈的最多就是实现web直播、摆脱插件,可以自定义集成等问题。我们熟悉的EasyNVR已经完美的解决了这些问题。然而对于web播放也存在一些问题,通常我们web播放RTMP

知了 | 基于NLP的智能问答推荐系统

作者简介:苗贝贝  百度高级研发工程师负责百度智能运维客服平台ChatOps,在时序数据异常检测、文本模式识别、相似度网络等方向也有广泛的实践经验。干货概览通常,客服系统主要有两种应答模式:机器人自动

使用 ES6 写 Koa Web 项目

完整代码:传送门我们node.js只是实现了部分ES6的语法,所以为了让我们ES6的代码能100%在node.js下执行,必须使用我们的babel把ES6代码编译成nodejs可执行的代码。node环

ES6系列之变量的解构赋值

1.什么是解构?ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。它在语法上比ES5所提供的更加简洁、紧凑、清晰。它不仅能减少你的代码量,还能从根本上改变你的编码方式。2.数

“设备+云管”双管齐下 H3C WAS6100交换机评测

俗话说“好马配好鞍,好船配好帆”。搭配是门技术活,对于企业组网来讲亦是如此。现如今,网络已成为企业业务的主要动脉,网速的快慢直接影响公司的办公效率,网络安全问题也成为公司最大的威胁。受制于成本和规模,

dw cs6怎么保存为css格式

dwcs6怎么保存为css格式1、首先,打开DreamweaverCS6,新建一个css文档,选中“css”,点击确定按钮。2、将设计好的css样式放入该页面,@charset"utf-8";用来指定

数据偏移、分区陷阱……我们这样避开DynamoDB的5个坑

摘要:本文主要介绍作者所在团队在具体业务中所遇到的挑战,基于这些挑战为何最终选型使用AmazonDynamoDB,在实践中遇到了哪些问题以及又是如何解决的。文中不会详细讨论AmazonDynamoDB

配置 Horizon 的 queue, balance, processes 参数以及 Redis 中的优先级

我假设你正在使用redis和 LaravelHorizon,要开始配置horizon,仅需用我下面的命令清空所有进程队列任务中horizon的仪表盘。我也曾在本系列的a教程中描述过 链接:phpar

MESH无线究竟有多强? Linksys MR8300无线路由器评测

作为正儿八经的“北漂一族”,常年的蜗居生活让我对大房子的概念渐渐模糊,房东提供的无线路由器也能够满足日常的网络需求。但前段时间回了一趟河北老家才发现,家里的无线路由器已经远远不能够满足我的组网需求。信