Async/Await 邊學邊練

Async/Await是ES2017中加入的新特性,解救衆生於Promisejavascript

這篇文章主要根據Async/Await的一個介紹視頻,截圖供你們入門學習java

1 發展歷史

 

callback最受詬病的就是嵌套的括號,不美觀,錯誤處理也複雜node

 

Promise就好不少,結構清晰,統一錯誤處理編程

 

主角Async/Await登場了,傳統的函數調用方式,線性編程方式dom

 

示例

注意:下面的示例須要在node>=7.6的環境下,支持async/wait異步

  • 1-sequential

 1-1-naive

 記錄兩個方法運行的時間,總共運行的時間async

 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() 用於將那些接受回調函數的函數,轉變爲 Promiseoop

 

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()

 

結果

  

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()

 

結果

 

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()

 

結果

 

  • 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()

 

結果

 

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()

 

結果

 

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()

 

結果

 

 

  • 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()

 

結果

 

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()

 

結果

 

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()

 

結果

 

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()

 

結果

 

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

相關文章
相關標籤/搜索