深入理解Promise

文章目录

*

+ Promise的前提概念
+ Promise参数和执行顺序
+ Promise的嵌套执行
+ Promise.prototype.then()
+ Promise.prototype.catch()
+ finally()
+ Promise.all()
+ race()
+ Promise.allSettled()
+ Promise.any()
+ Promise.resolve()
+ Promise.reject()
+ Promise.try()

Promise的前提概念

Promise是一个构造函数,用来生成Promise实例
Promise构造函数接受一个函数作为参数,该函数有两个参数,分别是 resolvereject
resolve:成功时的回调
reject:失败时的回调

Promise分别有三个状态
1、pending :进行中
2、fulfilled:已成功
3、rejected:已失败

Promise的执行
Promise一旦新建后就会立马执行,无法中途取消, Promise返回的只有两种状态,并且该状态产生就无法更改。也就是说 Promise的状态只有以下两种情况:
1、从 pendingfulfilled
2、从 pendingrejected
pending的状态一旦改变,就不会再发生变化。

Promise的结果返回
Promise内部结果一旦返回, resolvereject其中的任何一种,即可产生回调。
1、 resolve的回调在 then()中获取(成功的回调)
2、 reject的回调在 cathc()中获取(失败,捕获错误)

let promise = new Promise(function(resolve,reject){

     let i = 5;
     if( i > 1){
         resolve(i)
     } else {
         reject(error)
     }
})

promise.then(el=>{

     console.log(el);
    })
    .catch(err=>{
        console.log(err);
    })

Promise的执行顺序
Promise创建后会立马执行, then()是一个异步回调,将在所有的同步任务执行完后执行 then(),也就是说: Promise在新建的时候会立即执行, then()catch()为异步任务,当所有同步任务执行完后才会执行 then()

let pro = new Promise(function(resolve,reject){
    console.log('Promise新建');
    resolve()
})

pro.then(el=>{
   console.log('.then回调');
})
console.log('同步任务');

深入理解Promise
上述代码的执行结果:
1、Promise新建
2、同步任务
3、then()回调

Promise参数和执行顺序

resolve函数的参数出了可以携带正常值以外,还可以携带 Promise实例

let pro = new Promise(function(resolve,reject){
let i = 10
    if(i < 50){
        resolve(i)
    } else {
        reject(error)
   }
})

let pro2 = new Promise(function(resolve,reject){
    resolve(pro)
})

pro2.then(el=>{
     console.log(el);
    })
    .catch(err=>{
     console.log(err);
    })

执行顺序:
先执行 pro,如果 pro的状态是 pending时, pro2则会等待执行,当 pro的状态变成 resolverejected时, pro2则会立马执行,由于 pro决定 pro2的状态,所以后面的 then变成了针对 pro

Promise的嵌套执行

let p = new Promise((resolve,reject)=>{
     let i = 10
     if(i > 5){
         resolve(i)
     } else {
         reject('pro错误')
     }
})

let p2 = new Promise((resolve,reject)=>{
    p.then(el=>{
        console.log(el * 2);
        if(el > 6){

           resolve(el)
           console.log('我是p1的.then回调');
        } else {
            reject('pro2错误')
        }
    })
   })

let p3 = new Promise((resolve,reject)=>{
    p2.then(el=>{
        if(el > 50){
            resolve(el)
        } else {
            reject('pro3错误')
        }
    })
})

多个 Promise的执行顺序:
新建 Promise后会立马执行,先执行 Promise内的任务,执行完成后再执行 then()
如果 Promise内有其它 Promisethen()任务执行(这里简称 p2),会先将 p2then()任务执行完毕,再执行自身的 then()任务
多个 Promise并行,会先按顺序执行 Promise的任务,再分别按照顺序分别执行他们的 then()任务

需要 &#x6CE8;&#x610F;的是:上面 p2Promse中,正常来说, resolvereject执行完后, Promise的使命应该完成,但此处因为执行顺序的问题,并没有先执行 resolve,而是执行了 console的任务,因该写成 return resolve(value)的形式,让 Promise更正常一些,否则会出现不必要的意外。

Promise.prototype.then()

then方法是定义在原型对象 Promise.prototype上的,它可以为 Promise实例添加状态改变时的回调函数。
then有两个参数(可选):
resolved:成功状态的回调函数
rejected:失败状态的回调函数
then返回的是一个新的 Promise实例,因此可以采用链式写法, then()后面还可以接 then()

let p = new Promise((resolve,reject)=>{
    let i = 5;
    if(i > 4){
        resolve(i)
    }
})

p.then(el=>{
    console.log('then1:'+ el);
    if(el > 3){
       return el
    }
}).then(el=>{
    console.log('then2:'+ el * 2);
}).catch(err=>{
    console.log(err);
}

上面代码使用 then方法,第一个 then()回调函数执行完后,会将返回结果传入第二个回调函数,也就是说,第二个 then()的参数是第一个 then()返回的结果。
catch的捕获具有冒泡性质,也就是说,前面不论 .then了多少次,里面发生的错误,都会被最后一个 catch捕获到。

Promise.prototype.catch()

Promise.prototype.catch()方法是 .then(null,rejection)的别名,也就是说, catch其实是用来指定发生错误时的回调函数。

let p = new Promise((resolve,reject)=>{
        reject('错误信息')
   })

p.then(el=>{

  }).catch(err=>{
    console.log(err);
  })

上述代码中, p方法返回 Promise对象,该对象返回的是 rejectthen()方法调用回调函数, then()有两个参数,一个 resolvedrejected,如果 Promise返回的是 reject,那么 .then的状态就会变成 rejectedrejected会调用 catch()方法指定的回调函数,处理该错误, catch的参数就是 reject抛出的错误信息。

如果then运行中抛出错误,也会被catch()捕获

let p2 = new Promise((resolve,reject)=>{
    resolve(100)
   })
p2.then(el=>{
    throw new Error('then抛错')
}).catch(err=>{
    console.log(err);
})

catch捕捉错误的方式


let promise = new Promise(function(resolve,reject){
    try {
       throw new Error('方式一错误')
    } catch(e){
         reject(e)
    }
})

promise.catch(err=>{
   console.log(err);
   })

let promise2 = new Promise(function(resolve,reject){
    reject(new Error('方式二错误'))
})

promise2.catch(err=>{
      console.log(err);
   })

let promise3 = new Promise((resolve,reject)=>{
      reject('方式三错误')
   })

promise3.catch(err=>{
      console.log(err);
   })

以上三种效果是一样的,前两种通过 Error抛出异常,后一种直接抛出异常
catch返回的也是一个 Promise对象,后面还可以接着调用 then()方法
如果 Promise的状态变成 resolved,那么再抛出错误是无效的,因为 Promise的状态一旦发生改变,就会永久保持该状态。

执行阻塞问题
Promise内部错误不会影响到到异步队列中的 Promise外部代码,同步代码还是会造成阻塞

let p3 = new Promise((resolve,reject)=>{
      resolve(str)
})

p3.then(el=>{console.log(el)})
setTimeout(()=>{console.log('Promise外部代码')},1000)
console.log('同步代码');

深入理解Promise

finally()

finally有最后、终于的意思,也就是说 finally()方法不管 Promise最后的状态如何,都会执行

let p = new Promise((resolve,reject)=>{
            resolve('东方不败')
})
p.then(el=>{
    console.log(el);
})
.catch(err=>{
    console.log(err);
})
.finally(()=>
    console.log('finally执行')
)

深入理解Promise
上述代码中,不管 Promise最后的状态怎么样, finally都会执行,即使没有 then()catch()finally也会执行

需要注意的是, finally不接受任何参数,但是 finally的执行顺序跟内部是否是一个函数有关,如果 finally内部是一个函数,那么 finally会在 Promise最后执行,如果 finally内部没有任何函数,直接输出,那么 finally会在 Promise最前面执行。

finally的执行跟 Promise的状态无关。

Promise.all()

Promise.all()方法用于将多个 Promise实例包装成一个新的 Promise实例
语法: let p = Promise.all([p1,p2,p3])

let p = new Promise((resolve,reject)=>{
    resolve(10)
})
p.then(el=>{
    console.log(el);
})

let p2 = new Promise((resolve,reject)=>{

    reject(20)
})
p2.then(el=>{
    console.log(el);
})
.catch(err=>{console.log('p2:',err);})

Promise.all([p,p2])
       .then(el=>{
           console.log(el);
        })
        .catch(err=>{console.log('all:',err);})

Promise.all的两个 promise参数状态都变成 fulfilled时,才会触发 Promise.all()的方法,如果其中以一个参数被 rejected,那么 Promise.all()也会变成 rejected的状态,会被 catch捕捉。
上面代码中,如果 p2没有 chach方法,则会调用 Promise.all()catch

race()

Promise.race()方法可以将多个 Promise实例包装成一个新的 Promise实例。
语法: let p = Promise.race([p1,p2,p3])

let p = new Promise((resolve,reject)=>{
      setTimeout(()=>{
            resolve('p1状态')
      },2000)
    })

let p2 = new Promise((resolve,reject)=>{
      setTimeout(()=>{
            resolve('p2状态')
       },1000)
     })

let p3 = new Promise((resolve,reject)=>{
       setTimeout(()=>{
            resolve('p3状态')
       },3000)
     })

let p4 = new Promise((resolve,reject)=>{
       setTimeout(()=>{
            reject('reject:p4状态')
        },4000)
      })

let promise = Promise.race([p,p2,p3,p4])
promise
.then(el=>{
    console.log(el);
})
.catch(err=>{
    console.log(err);
})

深入理解Promise

race有竞争,角逐的意思,该方法其实就是参数中,哪一个 Promise的状态先发生改变,就调用先发生改变的 promise,这个 el就是最先发生改变的 promise的返回值。

Promise.allSettled()

Promise.allSettled()方法可以在所有异步操作都结束的情况下,调用该方法。它与 Promise.all()方法不同的是, all()方法需要所有异步都成功才会进入 then(),而 allSettled()不需要。

let p = new Promise((resolve,reject)=>{
      resolve('p1状态')
})

let p2 = new Promise((resolve,reject)=>{
       setTimeout(()=>{
         reject('p2状态')
       },3000)
})

Promise.allSettled([p,p2])
.then(el=> console.log(el) )

深入理解Promise

Promise.any()

Promise.any()方法接受一组 Promise实例作为参数,包装成一个新的 Promise实例返回。

let p = new Promise((resolve,reject)=>{
      resolve('p1状态')
})

let p2 = new Promise((resolve,reject)=>{
      reject('p2状态')
})

Promise.any([p,p2])
       .then(el=>{
          console.log('then:',el);
       })
       .catch(err=>{
          console.log('catch:',err);
       })

只要有一个参数的状态变成 fulfilledPromise.any就会变成 fulfilled状态
如果所有的参数实例都变成 rejected状态,包装实例才会变成 rejected状态
也就是说, any是只要有一个参数成功, any就可以 then,所有参数都 rejectany才会 catch

Promise.resolve()

Promise.resolve()可以将现有对象转为 Promise对象, Promise.resolve()方法就起到这个作用。
语法: let p = Promise.resolve(obj)

let p = Promise.resolve('obj')
p.then(el=> console.log(el))

let p2 = new Promise(resolve=>resolve('obj'))

如果 Promise.resolve()没有参数,那么将直接返回 resolved状态的 Promise对象,并且是一个没有参数的 then()方法。

let p3 = Promise.resolve()
p3.then(el=>{
     console.log(el);
})

setTimeout(()=>{
     console.log('定时器');
},0)

Promise.resolve()
       .then(()=>{
         setTimeout(()=>{console.log('resolve内定时器')},0)
         console.log('resolve内部');
        })
console.log('外部');

深入理解Promise

Promise.reject()

Promise.reject()返回一个新的 Promise实例,该实例的状态为 rejected

let p = Promise.reject('错误信息')
p.catch(err=>console.log(err))

let p2 = new Promise((resolve,reject)=>{
    reject('错误信息2')
})
p2.catch(err=>console.log(err))

深入理解Promise

Promise.try()

实际开发中,会遇到这么一种情况,不管函数是同步还是异步的,都想用 Promise来处理它,因为这样就可以用 then()指定下一步流程, catch处理抛出的错误,更便于管理流程。
基于 Promise我们可以用 async做到同步的代码风格执行异步操作,现在有一个最新的提案,使用 Promise.try()来捕获所有的同步和异步错误。
为什么这么做?
Promise抛出的错误, catch可以捕获到,但此处仅限于当前 Promise的异常错误,也就是异步的。如果同步错误抛出,那么 catch()是捕捉不到的,需要在外层再嵌套一层 try...catch,这样写起来非常麻烦,代码如下:

try {
   let p = new Promise((resolve,reject)=>{
           reject('异步错误')
       })
   p.catch(err=> void console.log(err) )
   throw Error('同步错误')

} catch (e) {
    console.log(e);
}

如果使用 Promise.try()就可以捕获所有的同步和异步错误

Promise.try(()=>{
    let p2 = new Promise((resolve,reject)=>{
        reject('异步错误2')
    })
         throw Error('同步错误2')
    })
    .then(el=>{
        console.log('then:',el);
     })
    .catch(err=>{
        console.log('catch:',err);
    })

此处的 Promise.try就相当于 try代码块, Promise.catch就相当于 catch代码块。

案例源码:https://gitee.com/wang_fan_w/es6-science-institute

如果觉得这篇文章对你有帮助,欢迎点亮一下star哟

Original: https://blog.csdn.net/qq_44793507/article/details/128737628
Author: fanction
Title: 深入理解Promise

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/812707/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球