async await实际上是语法糖,可以通过书写同步代码的方式,执行异步操作,内部实现其实就是通过generator和yield实现。await后面返回的是一个promise对象。
我们知道Promise与Async/await函数都是用来解决JavaScript中的异步问题的,从最开始的回调函数处理异步,到Promise处理异步,到Generator处理异步,再到Async/await处理异步,每一次的技术更新都使得JavaScript处理异步的方式更加优雅,从目前来看,Async/await被认为是异步处理的终极解决方案,让JS的异步处理越来越像同步任务。异步编程的最高境界,就是根本不用关心它是不是异步。
使用generator实现一个Async
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num*2)
}, 1000)
})
}
function *gen() {
let num1 = yield fn(1)
let num2 = yield fn(num1)
let num3 = yield fn(num2)
return num3
}
function generatorToAsync(gen) {
return function () {
// 返回一个promise
return new Promise((resolve, reject) => {
// 执行Generator函数
let g = gen();
let next = (context) => {
let res
try {
res = g.next(context);
} catch (error) {
reject(error)
}
// 这时候说明已经是完成了,需要返回结果
if (res.done) {
resolve(res.value);
}
// 继续执行next函数,传入执行结果
else {
return Promise.resolve(res.value).then(val => next(val), err => next(err))
}
}
next();
})
}
}
// 测试用generator实现的async函数
let f = generatorToAsync(gen);
f().then((res) => {
console.log('result=====', res);
})
// 和async对比
async function f2() {
let num1 = await fn(1)
let num2 = await fn(num1)
let num3 = await fn(num2)
return num3
}
f2().then((res) => {
console.log('result=====', res);
})
async与generator对比:
- 语法和可读性:
- async/await:语法简洁,代码结构类似于同步代码,便于理解和维护。
- 生成器:需要使用 yield 和 next 显式管理控制流,代码可能比 async/await 更加复杂。
- 错误处理:
- async/await:可以使用 try/catch 直接处理异步操作中的错误。
- 生成器:需要在控制流管理库(如 co)中处理错误,代码稍显复杂。
- 性能:
- async/await:基于 Promise 实现,性能开销较小。
- 生成器:可以在不借助外部库的情况下处理同步任务,但用于异步任务时需要额外的库,性能可能略有影响。
- 灵活性:
- async/await:设计用于处理异步操作,专为简化异步代码而生。
- 生成器:不仅可以处理异步操作,还可以处理复杂的同步控制流,但需要额外的库来处理异步操作。
总结:
- 使用 async/await 可以使异步代码更直观、可读性更强,适合大多数异步编程场景。
- 生成器适合复杂的控制流管理,尤其是需要暂停和恢复执行的场景。但用于异步编程时,通常需要结合外部库。