Async/Await 边学边练

本文介绍了 Async/Await 的发展历程及在 Node.js 中的应用实践,包括顺序与并行执行、循环处理等场景,并展示了如何优雅地处理异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Async/Await是ES2017中加入的新特性,解救众生于Promise

这篇文章主要根据Async/Await的一个介绍视频,截图供大家入门学习

1 发展历史

 

callback最受诟病的就是嵌套的括号,不美观,错误处理也复杂

 

Promise就好很多,结构清晰,统一错误处理

 

主角Async/Await登场了,传统的函数调用方式,线性编程方式

 

示例

注意:下面的示例需要在node>=7.6的环境下,支持async/wait

  • 1-sequential

 1-1-naive

 记录两个方法运行的时间,总共运行的时间

 processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    console.log('Process 01 started')
    console.time('Process 01 ended')
    await wait(5000)
    console.timeEnd('Process 01 ended')
    console.log()
    return 'process01-value'
  },

  async process02 () {
    console.log('Process 02 started')
    console.time('Process 02 ended')
    await wait(3000)
    console.timeEnd('Process 02 ended')
    console.log()
    return 'process02-value'
  }
}

第一行的util是nodejs自带的工具类,本机需要安装node

第二行util.promisify() 用于将那些接受回调函数的函数,转变为 Promise

 

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const value01 = await process01()
    const value02 = await process02()

    console.log('Process 01 Returned: ', value01)
    console.log('Process 02 Returned: ', value02)

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

155618_slOp_2510955.png

  
1-2-issue

异常处理,如果被调用函数没有处理异常,则会中断执行调用函数

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    console.log('Process 01 started')
    throw new Error('Process 01 Failed')
    console.time('Process 01 ended')
    await wait(5000)
    console.timeEnd('Process 01 ended')
    console.log()
    return 'process01-value'
  },

  async process02 () {
    console.log('Process 02 started')
    console.time('Process 02 ended')
    await wait(3000)
    console.timeEnd('Process 02 ended')
    console.log()
    return 'process02-value'
  }
}

 

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const value01 = await process01()
    const value02 = await process02()

    console.log('Process 01 Returned: ', value01)
    console.log('Process 02 Returned: ', value02)

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

160449_X5Kz_2510955.png

 

1-3-solution

针对1-2-issue的错误处理,在process01中增加了异常处理,不会中断调用函数的执行

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    try {
      console.log('Process 01 started')
      throw new Error('Process 01 Failed')
      console.time('Process 01 ended')
      await wait(5000)
      console.timeEnd('Process 01 ended')
      console.log()
      return 'process01-value'
    } catch (error) {
      console.error(error)
    }
  },

  async process02 () {
    try {
      console.log('Process 02 started')
      console.time('Process 02 ended')
      await wait(3000)
      console.timeEnd('Process 02 ended')
      console.log()
      return 'process02-value'
    } catch (error) {
      console.error(error)
    }
  }
}

               

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const value01 = await process01()
    const value02 = await process02()

    console.log('Process 01 Returned: ', value01)
    console.log('Process 02 Returned: ', value02)

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

161021_Wg0X_2510955.png

 

  • 02-parallel

2-1-naive

并行执行异步函数

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    console.log('Process 01 started')
    console.time('Process 01 ended')
    await wait(5000)
    console.timeEnd('Process 01 ended')
    console.log()
    return 'process01-value'
  },

  async process02 () {
    console.log('Process 02 started')
    console.time('Process 02 ended')
    await wait(3000)
    console.timeEnd('Process 02 ended')
    console.log()
    return 'process02-value'
  }
}

 

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const data = await Promise.all([process01(), process02()]) // 并行执行

    console.log()

    console.log('Process 01 Returned: ', data[0])
    console.log('Process 02 Returned: ', data[1])

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

161722_GQhZ_2510955.png

 

2-2-issue

并行执行2个函数,其中一个异步函数抛异常,不影响另一个函数的执行,但影响返回之后的操作

processes.js

 

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    console.log('Process 01 started')
    throw new Error('Process 01 Failed')
    console.time('Process 01 ended')
    await wait(5000)
    console.timeEnd('Process 01 ended')
    console.log()
    return 'process01-value'
  },

  async process02 () {
    console.log('Process 02 started')
    console.time('Process 02 ended')
    await wait(3000)
    console.timeEnd('Process 02 ended')
    console.log()
    return 'process02-value'
  }
}

 

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const data = await Promise.all([process01(), process02()]) // 并行执行

    console.log()

    console.log('Process 01 Returned: ', data[0])
    console.log('Process 02 Returned: ', data[1])

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

162723_BPhr_2510955.png

 

2-3-solution

被调用的异步函数添加异常处理,同样可以返回执行结果,不影响调用函数的继续执行

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

module.exports = {
  async process01 () {
    try {
      console.log('Process 01 started')
      throw new Error('Process 01 Failed')
      console.time('Process 01 ended')
      await wait(5000)
      console.timeEnd('Process 01 ended')
      console.log()
      return 'process01-value'
    } catch (error) {
      console.error(error)
    }
  },

  async process02 () {
    try {
      console.log('Process 02 started')
      console.time('Process 02 ended')
      await wait(3000)
      console.timeEnd('Process 02 ended')
      console.log()
      return 'process02-value'
    } catch (error) {
      console.error(error)
    }
  }
}

 

main.js

const {process01, process02} = require('./processes')

async function main () {
  try {
    console.time('Total Running Time')
    const data = await Promise.all([process01(), process02()]) // 并行执行

    console.log()

    console.log('Process 01 Returned: ', data[0])
    console.log('Process 02 Returned: ', data[1])

    console.log()

    console.timeEnd('Total Running Time')
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

163354_AvDG_2510955.png

 

 

  • 03-loops

3-1-for-loop

某个方法的benchmark, 循环执行10次,计算总耗时和平均耗时

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

function getRandBetween (a, b) {
  return Math.floor(Math.random() * b) + a
}

module.exports = {
  async secretAlgorithm () {
    console.time('secretAlgorithm')
    await wait(getRandBetween(1, 7) * 100)
    console.timeEnd('secretAlgorithm')
  }
}

 

main.js

const now = require('performance-now')
const {secretAlgorithm} = require('./processes')

const NUMBER_OF_RUNS = 10

async function main () {
  try {
    let totalTime = 0
    for (let i = 0; i < NUMBER_OF_RUNS; i++) {
      const start = now()
      await secretAlgorithm()
      const end = now()
      totalTime += (end - start)
    }
    console.log()

    console.log('totalTime: ', totalTime)
    console.log('Number of retries: ', NUMBER_OF_RUNS)
    console.log('Average Running Time: ', (totalTime / NUMBER_OF_RUNS).toFixed(3))

  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

163937_10W1_2510955.png

 

3-2-forEach

植5棵树,打印每棵树开关的时间, forEach中不能使用await, 可以使用 for...of 替代

PowerPlant.js

const util = require('util')
const wait = util.promisify(setTimeout)

function getRandBetween (a, b) {
  return Math.floor(Math.random() * b) + a
}
class PowerPlant {
  constructor (id) {
    this.id = id
  }

  async turnOn () {
    console.log(`Turning On Power Plant ${this.id}`)
    console.time(`Power Plant ${this.id} turned on`)
    await wait(getRandBetween(1, 5) * 200)
    console.timeEnd(`Power Plant ${this.id} turned on`)
    console.log()
  }

  async turnOff () {
    console.log(`Turning Off Power Plant ${this.id}`)
    console.time(`Power Plant ${this.id} turned off`)
    await wait(getRandBetween(1, 3) * 200)
    console.timeEnd(`Power Plant ${this.id} turned off`)
    console.log()
  }
}

module.exports = PowerPlant

 

main.js

const PowerPlant = require('./PowerPlant')
let powerPlants = []

async function main () {
  try {
    powerPlants.push(new PowerPlant('01'))
    powerPlants.push(new PowerPlant('02'))
    powerPlants.push(new PowerPlant('03'))
    powerPlants.push(new PowerPlant('04'))
    powerPlants.push(new PowerPlant('05'))

    /* turn on all of them */
    powerPlants.forEach(powerPlant => {
      await powerPlant.turnOn()
    })

    /* turn off all of them */
    powerPlants.forEach(powerPlant => {
      await powerPlant.turnOff()
    })
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

164417_XX0c_2510955.png

 

3-3-for-of

processes.js

const util = require('util')
const wait = util.promisify(setTimeout)

function getRandBetween (a, b) {
  return Math.floor(Math.random() * b) + a
}
class PowerPlant {
  constructor (id) {
    this.id = id
  }

  async turnOn () {
    console.log(`Turning On Power Plant ${this.id}`)
    console.time(`Power Plant ${this.id} turned on`)
    await wait(getRandBetween(1, 5) * 200)
    console.timeEnd(`Power Plant ${this.id} turned on`)
    console.log()
  }

  async turnOff () {
    console.log(`Turning Off Power Plant ${this.id}`)
    console.time(`Power Plant ${this.id} turned off`)
    await wait(getRandBetween(1, 3) * 200)
    console.timeEnd(`Power Plant ${this.id} turned off`)
    console.log()
  }
}

module.exports = PowerPlant

 

main.js

const PowerPlant = require('./PowerPlant')
let powerPlants = []

async function main () {
  try {
    powerPlants.push(new PowerPlant('01'))
    powerPlants.push(new PowerPlant('02'))
    powerPlants.push(new PowerPlant('03'))
    powerPlants.push(new PowerPlant('04'))
    powerPlants.push(new PowerPlant('05'))

    /* turn on all of them */
    for(let powerPlant of powerPlants) {
      await powerPlant.turnOn()
    }

    /* turn off all of them */
    for(let powerPlant of powerPlants) {
      await powerPlant.turnOff()
    }
  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

164851_q6di_2510955.png

 

3-4-while

某个方法的benchmark, 计算循环执行10次的耗时和平均耗时

processes.js
const util = require('util')
const wait = util.promisify(setTimeout)

function getRandBetween (a, b) {
  return Math.floor(Math.random() * b) + a
}

module.exports = {
  async secretAlgorithm () {
    console.time('secretAlgorithm')
    await wait(getRandBetween(1, 7) * 100)
    console.timeEnd('secretAlgorithm')
  }
}

 

main.js

const now = require('performance-now')
const {secretAlgorithm} = require('./processes')

const NUMBER_OF_RUNS = 10

async function main () {
  try {
    let totalTime = 0
    let retries = 0
    while (retries < NUMBER_OF_RUNS) {
      const start = now()
      await secretAlgorithm()
      const end = now()
      totalTime += (end - start)
      retries++
    }
    console.log()

    console.log('totalTime: ', totalTime)
    console.log('Number of retries: ', NUMBER_OF_RUNS)
    console.log('Average Running Time: ', (totalTime / NUMBER_OF_RUNS).toFixed(3))

  } catch (error) {
    console.error('error', error)
  }
}

main()

 

结果

165225_7aqk_2510955.png

 

https://www.youtube.com/watch?v=f57IHEeDNcA

转载于:https://my.oschina.net/u/2510955/blog/1558846

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值