每天3分钟,重学ES6-ES12(十五)异步代码处理方案

2022-09-19 14:19:26 浏览数 (1)


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 适用于 构建通用异步函数

0 人点赞