Promise

在异步操作里,处理未来可能发生的事情

用途:用来异步计算,将异步操作队列化,按照期望的顺序执行

为什么会有promise ?

javascript包含大量异步操作

异步操作可以避免页面冻结

解决回调地狱问题

以前都是用回调函数处理异步,以下模拟一个场景:

  function  requestData(url,successCallback,failtrueCallback) {
      setTimeout(() => {
        // 拿到请求的结果
        // url为pp请求成功
        if(url  ==='pp'){
          let name = ['abc','123']
          successCallback(name)
        }else{ // 否则请求失败
          let errMessage = '请求失败'
          failtrueCallback(errMessage)
        }
        
      }, 3000);
    }
    requestData('pp',(res)=>{
        console.log(res);  // ['abc', '123']
    },(err)=>{
        console.log(err);
    })

弊端:

1 如果是我们自己封装requestData,在封装的时候自己设计callback名称

2 用别人封装的request或者第三方库,需要了解别人的代码才能知道这个函数怎么获取结果,使用成本比较高

更好的方案,promise承诺(规范好了代码逻辑)

resolve 参数的三种特殊情况:

 1 普通值或对象  pending ---> fulfilled

    resolve(123)
    }).then(res => {
      console.log(res, 'res'); //123
    })

2 传入一个promise  状态由传入promise决定,相当于状态转移

  function foo(){
      return new Promise((resolve, reject) => {
        resolve(456)
      })
    }
    const fooPromise =  foo();


    new Promise((resolve, reject) => {
      resolve(fooPromise)
    }).then(res => {
      console.log(res, 'res'); //456
    })

3 传入一个对象,并且这个对象实现了有then 方法

const obj = {
      then: function (resolve, reject) {
        resolve(789);
      }
    }

    new Promise((resolve, reject) => {
      resolve(obj)
    }).then(res => {
      console.log(res, 'res'); //789
    })

promise的对象方法catch:(then catch finally )

无catch前:抛出异常,调用错误回调(.then的第二个参数)可读性差

const promise = new Promise((resolve, reject) => {
      //resolve('success')     
      //reject('error')
      throw new Error('报错')  //err 也会被捕获

    })
promise.then(undefined, err => {
      console.log(err, 'err');
    })

catch:传入错误捕获的回调函数(上面是catch的语法糖)不符合promise/a+ 规范,但是es6为了代码可读性,给了这种写法

 const promise = new Promise((resolve, reject) => {
      //resolve('success')     
      reject('error')
      //throw new Error('报错')  //err 也会被捕获

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

catch的回调是promise的,不是then后面的new Promise, 但是promise里面没有异常的话,也会捕获new Promise里面的,如果then 和catch 拆开写,那他们是相对独立,互不影响的

catch的返回值和then一样:

  promise.then(res=>{
      return new Promise((resolve, reject) => {    
        reject('then error')
      })
    }).catch(err => {
      console.log(err, 'err');
      return 'catch'
    }).then(res=>{
      console.log(res,'res'); // catch res
    }).catch(err=>{
      console.log(err,'err');
    })

finally 是es9新特性,不管变成fulfilled还是rejected状态,最终都会执行finally

promise.then(res=>{
      return new Promise((resolve, reject) => {    
        reject('then error')
      })
    }).catch(err => {
      console.log(err, 'err');
    }).finally(() => {
      console.log('我是必经之路!');
    })

promise类方法:resolve

promise.resolve方法相当于new Promise,并且执行resolve操作

把一个对象转成promise 

    const promise1 = Promise.resolve({a:'a'})
    console.log(promise1,'promise1');
    const promise2 = new Promise((resolve, reject) => {
      resolve({ a: 'a' })
    })
    console.log(promise2, 'promise2');

 promise类方法:Promise.all ,所有的promise都变成fulfilled再拿到结果, 但是有一个promise变成rejected,那整个promise是rejected ,对于还在处于pending状态的promise,获取不到结果

 const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
       resolve(111) 
      }, 1000);
      
    })
    const p2 = new Promise((resolve, reject) => {
       setTimeout(() => {
        reject(222)
      }, 3000);
    })
    const p3 = new Promise((resolve, reject) => {
       setTimeout(() => {
        resolve(333)
      }, 2000);
    })

    Promise.all([p1, p2, p3]).then((res)=>{
      console.log(res,'res');
    }).catch((err)=>{
      console.log(err,'err');   //err 222
    })

但是我不希望,reject阻断我其他的promise,于是乎:es11添加了新的API Promise.allSettled

这个方法会在所有promise都有结果,(无论是fulfilled,还是rejected)才会有最终的形态,且这个promise结果一定是fulfilled,不会走到catch



    Promise.allSettled([p1, p2, p3]).then((res)=>{
      console.log(res,'res');
    }).catch((err)=>{
      console.log(err,'err');
    })

  

 Promise.race : 有一个promise变成fulfilled就结束

 Promise.race([p1, p2, p3]).then((res)=>{
      console.log(res,'res');  // res 111
    }).catch((err)=>{
      console.log(err,'err');
    })

如果最先执行rejected,那么就会走catch ,输出 err 222  ,但是我想至少拿到一个结果,那么就会有另外一个方法:

 Promise.any : 和race很像,但是至少会返回一个正确结果(无catch)

但是三个请求都是rejected,如图所示

我们还可以通过error,errors拿到里面的数据 

  简单的实现一个promise: 

  //  设计 promise 

    // 保存状态
    const PRMOSE_STATUS_PENDING = 'pending'
    const PRMOSE_STATUS_FULFILLED = 'fulfilled'
    const PRMOSE_STATUS_REJECTED = 'rejected'
    class MyPromise {
      constructor(excutor) {
        this.status = PRMOSE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        const resolve = (value) => {
          if (this.status === PRMOSE_STATUS_PENDING) {
            this.status = PRMOSE_STATUS_FULFILLED
            setTimeout(() => {  // 定时器 宏任务 不会阻塞主线程 (promise是微任务)
              console.log('resolve');
              this.value = value
              // then传进来的回调
              this.onFilfilled(value)
            }, 0);


          }

        }

        const reject = (reason) => {
          if (this.status === PRMOSE_STATUS_PENDING) {
            this.status = PRMOSE_STATUS_REJECTED
            queueMicrotask(() => {
              console.log('reject');
              this.reason = reason
              this.onRejected(reason)
            })

            // then传进来的回调
          }
        }

        excutor(resolve, reject) //可以直接调用 promise参数 
      }

      then(onFilfilled, onRejected) {
        this.onFilfilled = onFilfilled
        this.onRejected = onRejected
      }
    }

    const promise = new MyPromise((resolve, reject) => {
      console.log("pending");
      resolve(111)
      reject(222)

    })

    // 调用then方法 
    promise.then(res => {
      console.log(res, 'res');
    }, err => {
      console.log(err, 'err');
    })

    promise.then(res => {  //  调用两次是覆盖,应该并存
      console.log(res, 'res');
    }, err => {
      console.log(err, 'err');
    })

   

目前还不能实现调用两次结果并存,链式调用,按顺序输出

调用两次结果并存

 //  设计 promise 

    // 保存状态
    const PRMOSE_STATUS_PENDING = 'pending'
    const PRMOSE_STATUS_FULFILLED = 'fulfilled'
    const PRMOSE_STATUS_REJECTED = 'rejected'
    class MyPromise {
      constructor(excutor) {
        this.status = PRMOSE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFilfilledFns= []
        this.onRejectedFns= []
        const resolve = (value) => {
          if (this.status === PRMOSE_STATUS_PENDING) {
            queueMicrotask(() => {  // 定时器 宏任务 不会阻塞主线程 (promise是微任务)
              // 执行微任务之前做判断
              console.log(this.status,'this.status');
              if(this.status !== PRMOSE_STATUS_PENDING) return
              this.status = PRMOSE_STATUS_FULFILLED
              console.log('resolve');
              this.value = value
              // then传进来的回调
              this.onFilfilledFns.forEach(fn=>{
                fn(this.value)
              })
            });
          }
        }

        const reject = (reason) => {
          if (this.status === PRMOSE_STATUS_PENDING) {  
            queueMicrotask(() => {
               // 执行微任务之前做判断
                console.log(this.status, 'this.status2');
               if (this.status !== PRMOSE_STATUS_PENDING) return
              this.status = PRMOSE_STATUS_REJECTED
              console.log('reject');
              this.reason = reason
              this.onRejectedFns.forEach(fn=>{
                fn(this.reason)
              })
            })
          }
        }

        excutor(resolve, reject) //可以直接调用 promise参数 
      }

      then(onFilfilled, onRejected) {  // 定时器的话不会调then 数据塞不到数组里,直接去调用
        // 如果then调用的时候,状态已经确认下来了 (包了一层定时器那个情况)
        if(this.status == PRMOSE_STATUS_FULFILLED && onFilfilled) {
         onFilfilled(this.value)
        }

        if (this.status == PRMOSE_STATUS_REJECTED && onRejected) {
          onRejected(this.reason)
        }
        // 将成功和失败的回调放在数组里
        if(this.status == PRMOSE_STATUS_PENDING){
          this.onFilfilledFns.push(onFilfilled)
          this.onRejectedFns.push(onRejected)
        }

      }
      
    }

    const promise = new MyPromise((resolve, reject) => {
      console.log("pending");
      resolve(111)
      reject(222)

    })

    // 调用then方法 
    promise.then(res => {
      console.log(res, 'res');
    }, err => {
      console.log(err, 'err');
    })

    promise.then(res => { 
      console.log(res, 'res');
    }, err => {
      console.log(err, 'err');
    })

    // 确定promise状态再调用then 
     setTimeout(() => {
       promise.then(res =>{
         console.log(res,'res2');
       })
     }, 1000);

链式调用

 // 保存状态
    const PRMOSE_STATUS_PENDING = 'pending'
    const PRMOSE_STATUS_FULFILLED = 'fulfilled'
    const PRMOSE_STATUS_REJECTED = 'rejected'
    class MyPromise {
      constructor(excutor) {
        this.status = PRMOSE_STATUS_PENDING
        this.value = undefined
        this.reason = undefined
        this.onFilfilledFns= []
        this.onRejectedFns= []
        const resolve = (value) => {
          if (this.status === PRMOSE_STATUS_PENDING) {
            queueMicrotask(() => {  // 定时器 宏任务 不会阻塞主线程 (promise是微任务)
              // 执行微任务之前做判断
              console.log(this.status,'this.status');
              if(this.status !== PRMOSE_STATUS_PENDING) return
              this.status = PRMOSE_STATUS_FULFILLED
              console.log('resolve');
              this.value = value
              // then传进来的回调
              this.onFilfilledFns.forEach(fn=>{
                fn(this.value)
              })
            });

          }

        }

        const reject = (reason) => {
          if (this.status === PRMOSE_STATUS_PENDING) {  
            queueMicrotask(() => {
               // 执行微任务之前做判断
                console.log(this.status, 'this.status2');
               if (this.status !== PRMOSE_STATUS_PENDING) return
              this.status = PRMOSE_STATUS_REJECTED
              console.log('reject');
              this.reason = reason
              this.onRejectedFns.forEach(fn=>{
                fn(this.reason)
              })
            })
          }
        }

        excutor(resolve, reject) //可以直接调用 promise参数 
      }

      then(onFilfilled, onRejected) {  // 定时器的话不会调then 数据塞不到数组里,直接去调用
        // 如果then调用的时候,状态已经确认下来了 (包了一层定时器那个情况)    
        return new MyPromise((resolve, reject) => {
           if (this.status == PRMOSE_STATUS_FULFILLED && onFilfilled) {
            try {
              const value = onFilfilled(this.value)
              resolve(value)
            } catch (err) {  //   // 抛出异常才会走reject
              reject(err)
            }
          }

          if (this.status == PRMOSE_STATUS_REJECTED && onRejected) {
            try {
              const value = onRejected(this.value)
              resolve(value)
            } catch (err) {     // 抛出异常才会走reject
              reject(err)
            }
          }
          // 将成功和失败的回调放在数组里
          if (this.status == PRMOSE_STATUS_PENDING) {
            this.onFilfilledFns.push(() => {
              try {
                const value = onFilfilled(this.value)
                resolve(value)
              } catch (err) {    // 抛出异常才会走reject
                reject(err)
              }
            })
            this.onRejectedFns.push(() => {
              try {
                const value = onRejected(this.value)
                resolve(value)
              } catch (err) {     // 抛出异常才会走reject
                reject(err)
              }
            })
          }

        })
      }
      
    }

    const promise = new MyPromise((resolve, reject) => {
      // resolve(111)
      resolve(222)
    })

    // 调用then方法多次调用
    promise.then(res => {
      console.log(res, 'res');
      return 'aaa'
    }, err => {
       return 'bbb'
      console.log(err, 'err');
    }).then(res => {
     
      console.log(res,'res2');
    },err => {
      console.log(err,'err2');
    })

优化一下,封装工具函数

 // 工具函数
    function a (exeFns, value, resolve, reject) {
        try {
          const result = exeFns(value)
          resolve(result)
        } catch (err) {    // 抛出异常才会走reject
          reject(err)
        }
      
    }

 then(onFilfilled, onRejected) {     
        return new MyPromise((resolve, reject) => {
           if (this.status == PRMOSE_STATUS_FULFILLED && onFilfilled) {
           a(onFilfilled, this.value, resolve, reject) 
          }

          if (this.status == PRMOSE_STATUS_REJECTED && onRejected) {
            a(onRejected, this.value, resolve, reject)
          }
          // 将成功和失败的回调放在数组里
          if (this.status == PRMOSE_STATUS_PENDING) {
            this.onFilfilledFns.push(() => {
               a(onFilfilled, this.value, resolve, reject)
            })
            this.onRejectedFns.push(() => {
              a(onRejected, this.value, resolve, reject)
            })
          }

        })
      }
      

手写promise_catch方法设计

.catch  是 reject 的语法糖

 const promise = new Promise((resolve, reject) => {
      //resolve('success')     
      reject('error')
      
    })
    promise.then(res=>{
      return new Promise((resolve, reject) => {    
        reject('then error')
      })
    }).catch(err => {
      console.log(err, 'err');
    })

正常来说拿到的应该是reject的回调但是 new Promise的回调,需要处理:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值