Js异步编程async/await 函数入门知识_异步菜鸟教程下载

提起异步编程,大家可能会想到事件监听、回调函数、发布订阅、Promise 对象、Generator 函数、async 函数等,本篇主要讲解的是 async 函数,很多人认为它是异步编程的终极解决方案。一、async 函数是什么?摘自阮老师的文章:一句话,它就是 Generator 函数的语法糖;也有人说它是 Promise 的语法糖。如果你对 Promise

Js异步编程async/await 函数入门知识

一、async 函数是什么?

摘自阮老师的文章:一句话,它就是 Generator 函数的语法糖;也有人说它是 Promise 的语法糖。

Js异步编程async/await 函数入门知识_异步菜鸟教程下载

如果你对 Promise 对象、 Generator 函数不是特别了解的话,建议先看一下阮老师 ECMAScript6 入门中的关于 Promise 对象 和 Generator 函数的介绍。

二、async

1.async 声明的函数的返回本质上是一个 promise 对象(很重要。。。)

就是说只要你声明了这个函数是 async,那么内部不管你怎么处理,它的返回肯定是个 Promise。

async function myAsync () {
   return 'hello world'
}
let result = myAsync()
console.log(result)

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

myAsync().then((val) => {
   console.log(val)
})

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

也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。

function getNum () {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(1000)
    }, 1000)
  })
}

async function myAsync () {
  let num = await getNum()
  return num + 1000
}

myAsync().then((val) => {
  console.log(val)
})

上面代码中,函数 myAsync 内部有两个操作:获取 num,加 1000 后并返回结果。只有这两个操作全部完成,才会执行 then 方法里面的 console.log(val)。

三、await

1.正常情况下,await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

2.await 的意思就是让 JavaScript 引擎等待,直到 await 命令后代码执行完毕,然后继续执行 await 命令后面的代码。

3.这个行为不会耗费 CPU 资源,因为引擎可以同时处理其他任务:执行其他脚本,处理事件等。

我们来看个例子,可以试着写出执行结果。

function myAwait () {
   return new Promise((resolve) => {
     resolve('hello world!')
   })
}

async function myAsync(){
   console.log('async begin')
   let wait = await myAwait()
   console.log(wait)
   console.log('async end')
   return wait
}

console.log('begin')
let result = myAsync()
console.log(result)
console.log('end')

以上结果是在谷歌浏览器下执行的结果,“async end” 在 “hello world!” 之后输出,因为 await 阻塞了 “async end” 的输出,但是 ‘end’ 在 “hello world!”之前输出了,因为 await 只会阻塞 async 函数中 await 后面代码的执行,不会阻塞其他代码的执行。

四、Promise 、Generator、async 异步编程示例

了解了 async 和 await 后,我们一起来看一个完整的例子。

假如我们做完一件事,需要分三个步骤,每一个步骤都需要上一步的执行结果,我们分别看一下 Promise 、 Generator 和 async 都是怎么实现的。

/* 花费时间 */
function takeLongTime (n) {
  return new Promise(resolve => {
    setTimeout(() => resolve(n + 1000), n)
  })
}

/* 步骤一 */
function step1 (n) {
  console.log(`step1 with ${n}`)
  return takeLongTime(n)
}

/* 步骤二 */
function step2 (n) {
  console.log(`step2 with ${n}`)
  return takeLongTime(n)
}

/* 步骤三 */
function step3 (n) {
  console.log(`step3 with ${n}`)
  return takeLongTime(n)
}

1. Promise 的实现:

function doIt () {
  let time1 = 1000
  step1(time1)
      .then(time2 => step2(time2))
      .then(time3 => step3(time3))
      .then(result => {
        console.log(`result is ${result}`)
      })
}

doIt()

2. Generator 的实现:

/** 执行器
  * Generator 函数不能自动执行,我们需要借助执行器
*/
function run (generator) {
  let iterator = generator()
  let result = iterator.next()
  function step () {
    if(!result.done) {
      let promise = Promise.resolve(result.value)
      promise.then((value) => {
        result = iterator.next(value)
        step()
      }).catch((error) => {
        result = iterator.throw(error)
        step()
      })
    }
  }
  step()
}

function *doIt () {
  let time1 = 1000
  let time2 = yield step1(time1)
  let time3 = yield step2(time2)
  let result = yield step3(time3)
  console.log(`result is ${result}`)
}

run(doIt)

3. async 的实现:

async function doIt () {
  let time1 = 1000
  let time2 = await step1(time1)
  let time3 = await step2(time2)
  let result = await step3(time3)
  console.log(`result is ${result}`)
}

doIt()

三种方法执行结果都如下:
Js异步编程async/await 函数入门知识_异步菜鸟教程下载

对比以上三种实现方式:

1.由于 Promise 的 then 方法返回的是一个新的 Promise,所以 Promise 可以通过链式调用实现异步编程。

2.async 函数和 Generator 函数就比较有意思了,async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await,并内置执行器,仅此而已。

3.不难发现,async 的写法更具语义化,并且更加清晰。

五、使用注意事项

1.await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await命令放在 try…catch 代码块中。

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另一种写法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}

2.多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

function getA () {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('A')
    }, 1000)
  })
}

function getB () {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('B')
    }, 1000)
  })
}

async function myAsync () {
  let A = await getA();
  console.log('A: ', A)
  let B = await getB();
  console.log('B: ', B)
}

myAsync()

上面代码中,getA 和 getB 是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有 getA 完成以后,才会执行 getB,完全可以让它们同时触发。

// 写法一
async function myAsync () {
  let [A, B] = await Promise.all([getA(), getB()])
  console.log('A: ', A)
  console.log('B: ', B)
}

myAsync()
// 写法二
async function myAsync () {
  let aPromise = getA()
  let bPromise = getB()
  let A = await aPromise
  let B = await bPromise
  console.log('A: ', A)
  console.log('B: ', B)
}

myAsync()

上面两种写法,getA 和 getB 都是同时触发,这样就会缩短程序的执行时间。

3.await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。

六、小结

函数前面的关键字 async 有两个作用:

1.让这个函数返回一个 promise
2.允许在函数内部使用 await,这个 await 关键字又让 JavaScript 引擎等待直到 promise 完成,如果有错误,就会抛出异常,否则,就返回结果。

这两个关键字一起用就提供了一个通俗易懂的方式来控制异步编程,并且易于读写。

七、附加题:async、promise、setTimeout 的执行顺序

相信你对 Promise、Generator、async 已经有了一定的了解了,若加上 setTimeout,你对代码的执行顺序还很清晰吗?

我们来看一道写出执行结果的题,相信很多同学面试的时候都遇到过,是不是很懵逼!!!

async function async1() {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
}

async function async2() {
   console.log('async2')
}

console.log('script start')

setTimeout(() => {
    console.log('setTimeout')
},0)

async1()

new Promise((resolve) => {
    console.log('promise1')
    resolve()
}).then(() => {
    console.log('promise2')
})

console.log('script end')

执行结果(不同浏览器执行结果可能不同,下面结果用的谷歌):

Js异步编程async/await 函数入门知识_异步菜鸟教程下载

请大家谨记执行规则:setTimeout 的优先级最低,没有 async 和 promise 级别高(其实 async 和 promise 是一样的,因为调用 async 方法时就是返回一个 promise 对象),async 和 promise 的 .then 就看谁先进入到的任务队列里面,任务队列里面有先进先出的概念。

按照这个规则,相信你很快就能写出执行结果了。

海计划公众号
(0)
上一篇 2020/03/26 23:29
下一篇 2020/03/26 23:29

您可能感兴趣的内容

  • vue router的使用菜鸟指南vue路由的相关知识_router小白入门

    1. 简介路由,工作原理与路由器相似(路由器将网线总线的IP分发到每一台设备上),Vue中的路由根据用户在网页中的点击,将其引导到对应的页面。2. 使用步骤安装vue-router或者直接引入vue-router.js(下载地址:https://router.vuejs.org/)例:SPA页面(Single Page Application,将一个网站的所

    2020/04/05
  • 为什么程序猿喜欢在深夜工作?原因万万没想到入门知识_程序员使用帮助

    常有人说,程序员就是种把咖啡因变为编码的机器。确实如果你随便抓个程序员来问他们什么时间工作状态最好,答案常常是:深夜!只是不同的人时间点早晚不同而已。有的会凌晨4点起床,在开始整天的疯狂工作前先完成一部分,这也成为一种普遍趋势。夜晚工作主要是为了避免干扰。但其实你也可以直接关门埋头做事就好了。对于程序员来说,这到底有什么特别原因呢我认为主要有三个原因:1.制

    2020/04/03
  • css怎么控制字间距?使用帮助_字体入门百科

    文字与文字间距距离,字与字距离间距如何设置?使用CSS设置字与字间距的方法如下:我们使用css样式属性letter-spacing:+距离数字+html单位如letter-spacing:15px;,即设置了字与字间距为15px(像素)。示例:HTML:

    实现字与字间距方法

    CSS:.box{letter-spacing:15px;}我们可

    2020/03/20
  • Remax小白基础_全新的小程序开发体验

    Remax小白基础 官方网址:https://remaxjs.org/ GitHub:https://github.com/remaxjs/remax 简介描述:全新的小程序开发体…

    2020/03/10
  • 什么是前端? web1.0、web2.0时代的网页制作,前端开发都有哪些内容等指南攻略_前端菜鸟知识

    一、 web1.0时代的网页制作网页制作是web1.0时代的产物,那个时候的网页主要是静态网页,所谓的静态网页就是没有与用户进行交互而仅仅供读者浏览的网页,我们当时称为“牛皮癣”网页。例如一篇QQ日志、一篇博文等展示性文章。在web1.0时代,用户能做的唯一事情就是浏览这个网站的文字图片内容,这时用户也不能像现在在大多数网站都可以评论交流(缺乏交互性)。相信

    2020/04/05
  • 数据库高并发解决方法总结菜鸟攻略_高并发使用帮助

    前言一个项目刚开始的时候是为了实现基本功能,随着版本和功能的迭代,大数据和高并发成了软件设计必须考虑的问题!本质很简单,一个是慢,一个是等。两者是相互关联的,因为慢,所以要等,因为等,所以慢,解决了慢,也就解决了等,解决了等,也就解决了慢。关键是如何解决慢和等,核心 一个是短,一个是少,一个是分流,最后一个是集群/横向扩张/读写分离/建立主从短是指路径要短页

    2020/04/03
  • 如何写出高性能的CSS3动画菜鸟攻略_css3动画基础指南

    小伙伴们在写CSS3动画时,会发现在手机上很多时候会感到卡顿,然后Google到的解决方案大多是开启GPU加速transform: translate3d(0,0,0); 可解决,但是为什么开启GPU加速就能让动画顺滑呢?
    我们从浏览器内部去理解下JS是单线程的,但是浏览器可以开启多个线程,渲染一个网页需要两个重要的线程来共同完成:Main Thread 主

    2020/04/06
  • DryIcons基础知识教程免费矢量图标素材下载网

    DryIcons基础入门 官方网址:http://dryicons.com/ 简介描述:免费矢量图标素材下载网 DryIcons:免费矢量图标素材下载网是一个提供免费矢量素材、图标…

    2020/03/05
  • MVC设计思想小白帮助_MV基础入门

    MVC是一种软件架构的思想,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离;(1)模型: 业务逻辑包含了业务数据的加工与处理以及相应的基础服务(为了保证业务逻辑能够正常进行的事务、安全、权限、日志等等的功能模块);(2)视图:展现模型处理的结果;另外,还要提供相应的操作界面,方便用户使用。(3)控制器:视图发请

    2020/03/31
  • css/html 空格,html空格符的显示、标示方式【html空格代码】小白指南_html菜鸟教程网

    在html里面空格的话,你直接敲打出来的空格是不可以的,下面将通过html和css中设置显示空格的实现总结:Html中空格符号编号描述 不断行的空白(1个字符宽度),不换行空格 全称No-Break Space,它是最常见和我们使用最多的空格,大多数的人可能只接触了 ,它是按下space键产生的空格。在HTML中,如果你用空格键产生此空格,空格是不会累加

    2020/04/06
  • Qatrix小白基础_一款超轻量级JS框架

    Qatrix基础入门 官方网址:http://qatrix.com GitHub:https://github.com/catfan/Qatrix 简介描述:一款超轻量级JS框架 …

    2020/03/06
  • 是不是人人都可以做程序员?入门教程_程序员使用帮助

    最近刚忙完一个项目,在做项目总结的时候,有一个强烈的感觉,同样都是带出两年的徒弟,在项目实际开展过程中展示的成果结果差别都有几倍的关系了。大家都是在一个起跑线上为啥差异这么大?是不是什么人都能做程序员?一系列的疑问在脑中呈现,这么多疑问归结起来:什么样的人适合做程序员?善于思考发现总结问题,并且积极的进补的人。程序员是一个对细节把控相当严苛的职业,无数的细节

    2020/04/03
  • 初级程序员如何提升自己?入门攻略_程序员零基础入门

    1、牢记基础,领悟原理无论各行各业,基础是最关键的。好比你是个大作家,结果老提笔忘字,提笔忘词,那么你又如何写出精美的文章呢。做程序开发也是如此,既要清楚基本技术,也要深刻领悟其原理,这样在以后的开发过程中才能运用自如。2、精于数据库,了解操作系统这一块,往往是新手忽视的,想要成为高手,必须精通这些。当然,对于刚刚入门的新手,可以一步一步的领悟。只有了解操作

    2020/03/23
  • modern-js-cheatsheet小白入门_在现代项目中经常遇到的JavaScript知识的速查表

    modern-js-cheatsheet小白入门 官方网址:https://mbeaudru.github.io/modern-js-cheatsheet/ GitHub:http…

    2020/03/07
  • Han基础教程_「汉字标准格式」印刷品般的汉字排版框架

    Han基础教程 官方网址:https://hanzi.pro/ GitHub:https://github.com/ethantw/Han 简介描述:「汉字标准格式」印刷品般的汉字…

    2020/03/06
  • Vue3.0 响应式数据入门攻略_响应式攻略教程

    “别再更新了,实在是学不动了”这句话道出了多少前端开发者的心声,”不幸”的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了。既来之则安之,扶我起来我要开始讲了。Vue3.0 为了达到更快、更小、更易于维护、更贴近原生、对开发者更友好的目的,在很多方面进行了重构:使用 Typescript

    2020/03/23