JavaScript高级(十四)----prmise

 异步请求的处理方式

回调函数

所谓的回调函数就是函数作为参数的传递,在一个函数内部调用另一个函数,调用的同时可以把内部函数的数据传递出来,他的使用场景就是异步操作,数据需要等待一段时间才能返回的情况下可以使用回调函数

    function foo(url, successCallback, failtureCallback) {
      // 假设这是网络请求,需要请求完毕才能返回给用户使用
      setTimeout(() => {
        if (url === 'success') {
         // 假设successCallback callback === 'function'
          successCallback && successCallback({ code: '200', message: '请求成功' })
        } else {
         //failtureCallback callback === 'function'
          failtureCallback && failtureCallback({ code: '-200', message: '请求失败' })
        }
      }, 2000)
    }

    foo('failture',
      res => console.log(res),
      err => console.log(err)
    )

回调函数处理异步的弊端

  • 如果是我们自己封装的函数,那么我们在封装的时候必须要自己设计好callback名称, 并且使用好,否则容易造成不理解。
  • 如果我们使用的是别人封装的函数或者一些第三方库, 那么我们必须去看别人的源码或者文档, 才知道它这个函数需要怎么去获取到结果。
  • 异步嵌套太多,容易造成回调地狱,代码看起来很不容易理解,可维护可阅读性都不高,找bug要花很多时间。
  •  function foo(url, successCallback, failtureCallback) {
          // 假设这是网络请求,需要请求完毕才能返回给用户使用
          setTimeout(() => {
            if (url === 'success') {
              successCallback && successCallback({ code: '200', message: '请求成功' })
            } else {
              failtureCallback && failtureCallback({ code: '-200', message: '请求失败' })
            }
          }, 1000)
        }
    
        foo('success',
          // 成功回调
          (res) => {
            console.log(`第一次数据请求成功,接着请求第二次数据${res.code}`)
            foo('success', (res) => {
              console.log(`第二次数据请求成功,接着请求第三次数据${res.code}`)
              foo('success', (res) => {
                console.log(`第三次数据请求成功,接着请求第四次数据${res.code}`)
                foo('success', (res) => {
                  console.log(`第四次数据请求成功,接着请求第五次数据${res.code}`)
                  foo('success', (res) => {
                    console.log(`第五次数据请求成功,接着请求第六次数据${res.code}`)
                    foo('failture', (res) => {
                      console.log(`第六次数据请求成功,接着请求第七次数据${res.code}`)
                    }, (err) => { console.log(`第六次数据请求失败,gg了${err.code}`) })
                  }, (err) => { console.log(err) })
                }, (err) => { console.log(err) })
              }, (err) => { console.log(err) })
            }, (err) => { console.log(err) })
          },
          // 失败回调
          (err) => { console.log(err) })
    

    上面代码就是典型的回调地狱,试问,如果你在真实项目开发中遇见这样的代码,你能够分析出问题的所在吗?所以这不是一种合理解决异步的方案。

Promise

Promise是一个类,实现异步编程的方法。

Promise的状态一旦被确定下来,无法被更改,resolve、reject两个函数不会代码禁止向下执行,为了防止继续向下执行,要加上return。

Promise的三个状态

  • 待定( pending ) : 初始状态,既没有被兑现,也没有被拒
  • 已兑现( fulfilled ) : 意味着操作已经完成 resolve
  • 已拒绝 (rejected):意味着操作失败 reject

resolve不同值的区别

  • 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数
  const promise = new Promise((resolve, reject) => { resolve("普通值") });

    promise.then(res => {
      console.log(res)
    }, err => { })
    
  • 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
     const promise = new Promise((resolve, reject) => {
      resolve(new Promise((resolve, reject) => {
        reject("我是新的promies, 我要改变之前promise的状态,这里会执行err")
      }))
    });

    promise.then(res => {
      console.log(res)
    }, err => {
      console.log(err)
    })
  • 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据 then方法的结果来决定Promise的状态
        const promise = new Promise((resolve, reject) => {
          const obj = {
            name: 'obj',
            then(resolve, reject) {
              reject('传入一个对象,对象里面有then方法,会改变之前promise的状态')
            }
          }
          resolve(obj)
        });
    
        promise.then(res => {
          console.log(res)
        }, err => {
          console.log(err)
        })
    

    then 方法的参数

        // then方法接受两个参数
        new Promise((resolve, reject) => {
          reject('嘿嘿')
        }).then(
          res => {
            console.log('resolve触发的回调函数');
          },
          err => {
            console.log('reject触发的回调函数');
          }
        )
        
        // 等价于
        new Promise((resolve, reject) => {
          reject('嘿嘿')
        })
          .then(res => { console.log('resolve触发的回调函数') })
          .catch(err => { console.log('reject触发的回调函数') })
    

    then 方法多次调用

        const promise = new Promise((resolve, reject) => {
          reject('嘿嘿嘿')
        })
    
        promise.then(res => { console.log(res) }).catch(err => { console.log(err) })
        promise.then(res => { console.log(res) }).catch(err => { console.log(err) })
    

    then/catch 方法返回值

    then/catch方法本身返回的就是一个Promise,所以我们可以进行链式调用。

  •     // catch打印完后又返回了一个promise 所以后面的then又会打印
        new Promise((resolve, reject) => {
          reject('嘿嘿')
        })
          .then(res => { console.log('resolve触发的回调函数'); })
          .catch(err => { console.log('reject触发的回调函数'); return 123 })
          .then(res => { console.log(res) })
    

    finally 方法

    finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会被执行的代码

        new Promise((resolve, reject) => {
          reject('reject')
        })
          .then(res => { console.log(res) })
          .catch(err => { console.log(err) })
          .finally(() => { console.log('我是最后被执行的') })
    

    all 方法

    它的作用是将多个Promise包裹在一起形成一个新的Promise。新的Promise状态由包裹的所有Promise共同决定。

        // 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组; 
        const p1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('1')
          }, 1000)
        })
    
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('2')
          }, 2000)
        })
    
        const p3 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('3')
          }, 3000)
        })
    
        Promise.all([p3, p2, p1]).then(res => {
          console.log(res)
        }).catch(err => {
          console.log(err)
        })
    
        //当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;
        const p1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('1')
          }, 1000)
        })
    
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            reject('2')
          }, 2000)
        })
    
        const p3 = new Promise((resolve, reject) => {
          setTimeout(() => {
            reject('3')
          }, 3000)
        })
    
        Promise.all([p3, p2, p1]).then(res => {
          console.log(res)
        }).catch(err => {
          console.log(err)
        })
    

    allSettled 方法

    all方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。

    该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态。

    const p1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(11111)
          }, 1000);
        })
    
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            reject(22222)
          }, 2000);
        })
    
        const p3 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(33333)
          }, 3000);
        })
    
        // allSettled
        Promise.allSettled([p1, p2, p3]).then(res => {
          console.log(res)
        }).catch(err => {
          console.log(err)
    

    race 方法

    如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法。

        const p1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('1')
          }, 1000)
        })
    
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            reject('2')
          }, 998)
        })
    
        const p3 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('3')
          }, 1002)
        })
    
        // 不管是resolve 还是reject  谁先有结果,那么就使用谁的结果
        Promise.race([p1, p2, p3])
          .then(res => { console.log(res) })
          .catch(err => { console.log(err) })
    

    any 方法

    和race方法是类似的,any方法会等到一个fulfilled状态,才会决定新Promise的状态,如果所有的Promise都是reject的,那么会报一个AggregateError的错误。

        const p1 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('1')
          }, 1000)
        })
    
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => {
            reject('2')
          }, 998)
        })
    
        const p3 = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('3')
          }, 1002)
        })
    
        // 会打印p1 
        Promise.any([p1, p2, p3])
          .then(res => { console.log(res) })
          .catch(err => { console.log(err) })
    

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值