theme: juejin
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
每天3分钟,重学ES6-ES12文章汇总
前言
今天开始和大家一起系统的学习ES6 ,每天3分钟,用一把斗地主的时间,重学ES6 ,前面我们介绍了promise,生成器和迭代器,async await,现在我们总结一下针对异步代码处理方案
业务场景
请求一个接口,拿到返回值,对返回值进行处理,当作第二个接口的请求参数,拿到返回值处理,当作第三个接口的请求参数。最终数据需要调用依次调用3个接口才能拿到。
1> url: why -> res: why
2> url: res "aaa" -> res: whyaaa
3> url: res "bbb" => res: whyaaabbb
代码语言:javascript复制function requestData(url) {
// 异步请求的代码会被放入到executor中
return new Promise((resolve, reject) => {
// 模拟网络请求
setTimeout(() => {
// 拿到请求的结果
resolve(url)
}, 2000);
})
}
方案一 回调函数
优点:便于理解 缺点:回调地狱,不能捕获错误
代码语言:javascript复制ajax('url', () => {
// callback 函数体
ajax('url', () => {
// callback 函数体
ajax('url', () => {
// callback 函数体
})
})
})
方案二 事件监听
代码语言:javascript复制f1.on('done', f2);
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}
优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数;
缺点:整个流程都要变成事件驱动型,运行流程会变得不清晰。
方案三 发布订阅模式
代码语言:javascript复制jQuery.subscribe("done", f2);
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done");
}, 1000);
}
jQuery.unsubscribe("done", f2);
与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
方案四 Promise中then的返回值来解决回调问题
代码语言:javascript复制requestData("why").then(res => {
return requestData(res "aaa")
}).then(res => {
return requestData(res "bbb")
}).then(res => {
console.log(res)
})
优点:解决了层层回调问题,相对直观 缺点:无法精确捕获到哪个promise错误,链式调用依然不如同步函数代码直观
方案五 Promise generator实现
代码语言:javascript复制function* getData() {
const res1 = yield requestData("why")
const res2 = yield requestData(res1 "aaa")
const res3 = yield requestData(res2 "bbb")
const res4 = yield requestData(res3 "ccc")
console.log(res4)
}
// 1> 手动执行生成器函数
const generator = getData()
generator.next().value.then(res => {
generator.next(res).value.then(res => {
generator.next(res).value.then(res => {
generator.next(res)
})
})
})
// 2> 自己封装了一个自动执行的函数
function execGenerator(genFn) {
const generator = genFn()
function exec(res) {
const result = generator.next(res)
if (result.done) {
return result.value
}
result.value.then(res => {
exec(res)
})
}
exec()
execGenerator(getData)
优点:代码直观,* yield 可以重新组织代码,同步的方式执行异步代码
缺点:无法执行并发请求,只能调用next()一步一步请求,* yield 对开发者不太友好,难以理解
方案六 async/await
代码语言:javascript复制async function getData() {
const res1 = await requestData("why")
const res2 = await requestData(res1 "aaa")
const res3 = await requestData(res2 "bbb")
const res4 = await requestData(res3 "ccc")
console.log(res4)
}
getData()
async 是generator的语法糖 内置执行器,无需手动执行next()方法
*/yield => async/await
优点:在generator 的基础上更加语义化,使用简单,无需执行next 方法 缺点:无法执行并发请求,必须有try catch才能捕获到异常
业务使用
Promise async/await
async/await是基于generator的语法糖,返回的也是一个promise,所以返回值可以调用promise的方法。 当处理并发一般Promise.all async/awit 结合使用
代码语言:javascript复制async function getData(){
await Promise.all([requestData(a),requestData(b)])
}
总结
async await意义在于‘期望异步代码和同步代码可以流畅混淆而不至于被 then 分割’。同步代码不多的情况,async await和promise的使用可以取决于个人喜好。
async/await设计初衷并不是为了取代Promise,而是为了让使用Promise更加方便。
JS异步的发展历程是callback->promise/generator->async/await
这三种历程我认为并没有 相互优越的区别,而是有使用场景的区别
注册事件必须是用回调,async await 可以梳理平常的业务代码 更容易理解拆分业务 ,而generator 适用于需要暂停的业务逻辑,promise 适用于 构建通用异步函数