Promise链式调用用法

1.首先需要知道什么是回调函数

我们在写代码时可能会碰到一些异步代码,而这些异步代码中,往往会有伴随着回调函数,就比如:

setTimeout(function(){
  console.log(1)
},3000)

这就是一个异步代码,相反的就是同步代码,同步代码会在主线程上运行,只有前面的任务运行完后才会执行后面的任务,异步代码会进入异步队列,这里一般会先执行同步代码,在同步代码执行完后,在从异步队列中抓取异步任务执行。上面的匿名函数就是一个回调函数,回调函数不会立即执行,会在满足一定条件下,才会执行。

2.了解回调地狱的造成原因

而我们有时不得会处理一些回调函数嵌套问题,就比如:

        setTimeout(function () {  //第一层
            console.log('1');
            setTimeout(function () {  //第二程
                console.log('2');
                setTimeout(function () {   //第三层
                    console.log('3');
                }, 1000)
            }, 2000)
        }, 3000)

我们想要这样的代码正常按顺序运行(按顺序输出1,2,3),往往会采取这种回调函数嵌套的形式,但是这种会造成一种问题,就是回调地狱。这会造成代码可读性差,牵一动全身的问题。

1.在Ajax中也会遇到这样的问题
 myAxios({
            url: 'http://hmajax.itheima.net/api/province',
        }).then((result) => {
            const pname = result.list[0]
            document.querySelector('.province').innerHTML = pname
            myAxios({
                url: 'http://hmajax.itheima.net/api/city',
                params: {
                    pname: pname 
                }
            }).then((result) => {
                const cname = result.list[0]
                document.querySelector('.city').innerHTML = cname
                myAxios({
                    url: 'http://hmajax.itheima.net/api/area1',
                    params: {
                        pname,
                        cname
                    }
                }).then((result) => {
                    document.querySelector('.area').innerHTML = result.list[0]
                })
            })
        }).catch((error) => {
            console.dir(error)
        }) myAxios({
            url: 'http://hmajax.itheima.net/api/province',
        }).then((result) => {
            const pname = result.list[0]
            document.querySelector('.province').innerHTML = pname
            myAxios({
                url: 'http://hmajax.itheima.net/api/city',
                params: {
                    pname: pname 
                }
            }).then((result) => {
                const cname = result.list[0]
                document.querySelector('.city').innerHTML = cname
                myAxios({
                    url: 'http://hmajax.itheima.net/api/area1',
                    params: {
                        pname,
                        cname
                    }
                }).then((result) => {
                    document.querySelector('.area').innerHTML = result.list[0]
                })
            })
        }).catch((error) => {
            console.dir(error)
        })

就比如这段代码(这里的myAxios模仿axios的,基本原理一样),是想要获取网址里的数据,并将其打印到页面上,但是发现第一个获取省名的参数需要传到下面的代码中,相同的第二个获取城市名的参数也需要传参到下面的代码中,这样不断叠加,就会造成回调地狱的问题。

从里面异步代码中抛出的问题,最外层无法接收到,而内层的代码也是耦合度非常高。

3.使用链式调用法解决回调地狱

1.首先我们需要了解Promise的原理,Promise本身分为三种状态,pending,resolved,rejected三种状态,这三种状态不会从一种状态转化到另一种状态
2.了解then属性的原理,then是Promise的一个属性,其中有两个参数一个是resolved,另一个是rejected,但Promise对象从pending状态状态转换到resolved是会调用函数1,若是转换到rejected则会调用函数2
p.then(函数1[,函数2])
3.then的返回值,then()方法的返回值也是一个promise对象,所以它支持链式写法。但是要注意的是它的返回值是一个新的promise对象,与调用then方法的并不是同一个对象。
4.换句话说,then()会封装一个全新的promise对象p2。那既然 p2也是一个promise对象,那么,p2的状态(promiseStatus)和值(promiseValue)分别是什么?规则如下:

如果p1的状态是pending,则p2的状态也是pending。

•如果p1的状态是resolved,then()会去执行f_ok,则p2的状态由f_ok的返回值决定。

•如果f_ok返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_ok函数的return值。•如果f_ok返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。•如果f_ok这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

如果p1的状态是rejected,then()会去执行f_err,则p2的状态由f_err的返回值决定。

•如果f_err返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_err函数的return值。•如果f_err返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。

•如果f_err这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

5.这样我们就可以利用then这种返回值所创建的新的Promise对象,实现链式调用
  let pname = ''
    myAxios({
      url: 'http://hmajax.itheima.net/api/province'
    }).then((result) => {
      // console.log(result.list[0])
      pname = result.list[0]
      document.querySelector('.province').innerHTML = pname
      return myAxios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
    }).then((result) => {
      // console.log(result.list[0])
      const cname = result.list[0]
      document.querySelector('.city').innerHTML = cname
      return myAxios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })
    }).then((result) => {
      // console.log(result)
      document.querySelector('.area').innerHTML = result.list[0]
    })

这种不断利用then创建新的Promise对象,实现了Promise的链式调用,从而解决了回调地狱。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值