解决回调地狱的方法:Promise、async/await、Generator

什么是回调函数?

当一个函数作为参数传入另一个参数中,并且它不会立即执行,只有当满足一定条件后该函数才可以执行,这种函数就称为回调函数。定时器和Ajax中就存在有回调函数。

定时器:

setTimeout(function () {
      console.log("执行回调函数")
}, 3000)

这里的function () {console.log("执行回调函数")}就是回调函数,在3秒后执行。

Ajax:

// 创建异步对象
const xhr = new XMLHttpRequest();
// 请求路径
const url = 'http://localhost:3000/getData';
// 绑定监听事件
xhr.onreadystatechange = function () {
    console.log(this.readyState);
    // 这个方法会被调用4次,最后一次readyState=4,并且status=200时才是最终想要的响应结果
    if (this.readyState == 4 && this.status == 200) {
      // 响应数据
      const response = xhr.responseText;
      console.log(response);
    }
}
// 创建请求
xhr.open('GET', url);
// 发送请求
xhr.send();

这里onreadystatechange绑定的函数就是回调函数,在发送请求并拿到响应后执行

什么是回调地狱?

回调地狱是只在异步js里,回调函数写的太多了,回调套回调,导致代码的可读性下降。

需求执行先执行步骤一,然后再执行步骤二,然后在执行步骤三。

回调地狱的写法:

setTimeout(function () {
      console.log("步骤一")
      setTimeout(function () {
        console.log("步骤二")
        setTimeout(function () {
          console.log("步骤三")
        }, 1000)
      }, 1000)
}, 1000)

怎么解决回调地狱?

1、使用Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。它最早由社区提出并实现,ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。

  • Promise构造函数接收一个函数作为参数,我们需要处理的异步任务就写在该函数体内,该函数的两个参数是resolve,reject。异步任务执行成功时调用resolve函数返回结果,反之调用reject。
  • Promise对象的then方法用来接收处理成功时响应的数据,catch方法用来接收处理失败时相应的数据。
  • Promise的链式编程可以保证代码的执行顺序,前提是每一次在then做完处理后,一定要return一个Promise对象,这样才能在下一次then时接收到数据。
const getOne = function (id) {
      console.log('步骤一:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 1});
      })
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 2});
      })
}
const getThree = function (id) {
      console.log('步骤三:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 3});
      })
}

getOne('one').then((res) => {
      console.log(res);
      return getTwo('two')
}).then((res) => {
      console.log(res);
      return getThree('three')
}).then((res) => {
      console.log(res)
}).catch((e) => {
      console.log(e);
})

2、使用async/await

它是es8的新特性
async和await结合可以让异步代码像同步代码一样

  • async表示这是一个async函数,await必须写在async函数中
  • await右侧的表达式一般为promise对象
  • await返回的是promise成功的值
  • await的promise失败了就会抛出异常,需要通过try…catch捕获处理
  • 返回的结果如果不是一个Promise对象(return 字符串,数字类型等,undefined等),则函数返回的结果就是一个成功的Promise对象
  • 如果返回的结果是一个promise对象,则成功的promise 的值就是该函数成功的值
const getOne = function (id) {
      console.log('步骤一:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 1});
      })
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 2});
      })
}
const getThree = function (id) {
      console.log('步骤三:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 3});
      })
}

const makeRequest = async () => {
      try {
        const data1 = await getOne('one');
        console.log(data1)
        if (data1) {
          const data2 = await getTwo('two');
          console.log(data2)
          if (data2) {
            const data3 = await getThree('three');
            console.log(data3)
          }
        }
      } catch (e) {
        console.log(e)
      }
}
makeRequest();

3、使用Generator

Generator是ES6提出的一种异步编程的方案。因为手动创建一个iterator十分麻烦,因此ES6推出了generator,用于更方便的创建iterator。也就是说,Generator就是一个返回值为iterator对象的函数。

Generator(生成器)是一种函数,声明方式和普通函数类似,只不过要在function后面加个*(function*),
Generator(生成器)是一特殊的函数,定义方式和执行方式和普通函数不一样。

  • 生成器是一个特殊的函数(在函数名前面加一个*号),用来解决异步编程的回调地狱问题,语法行为和传统函数完全不同。
  • yield 语句是函数代码的分隔符,把函数代码切割成几块通过 next() 来控制代码的一个向下的执行。
  • 使用 iterator 迭代器对象说明可以使用 for...of 来遍历,每一次调用返回的结果是 yield 后面的内容。
  • next 执行的时候是可以传参的,参数将作为上一个 yield 语句整体返回结果。
const getOne = function (id) {
      console.log('步骤一:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 1});
      }, 1000);
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 2});
      }, 1000);
}
const getThree = function (id) {
      console.log('步骤三:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 3});
      }, 1000);
}

function* gen() {
      const data1 = yield getOne('one');
      console.log(data1)
      const data2 = yield getTwo('two');
      console.log(data2)
      const data3 = yield getThree('three');
      console.log(data3)
}

let iterator = gen();
iterator.next();

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值