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