js-Promise

124 阅读4分钟

Promise是什么

  1. 抽象表达
  • Promise是Es6规范
  • Promise是JS中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
  1. 具体表达
  • 从语法上来说:Promise是一个构造函数
  • 从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

为什么要使用Promise

  1. promise支持链式调用,能解决回调地狱。回调地狱:不便于阅读;不便于异常处理
  2. 指定回调函数的方式更加灵活
    • 旧的:必须在启动异步任务之前指定
    • promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以再异步任务结束后指定多个)

promise的状态改变

实例对象中的一个属性 [PromiseState]

  • pending 未决定的
  • resolved/fullfilled成功
  • rejected 失败
  1. pending变为resolved
  2. pending变为rejected 说明:只有这两种,且一个promise对象只能改变一次;无论变为成功还是失败,都会有一个结果数据;成功的结果数据一般称为value,失败的结果数据一般称为reason

Promise对象的值

实例对象中的另一个属性 [PromiseResult] 保存着对象成功/失败的结果

  • resolve
  • reject

如何使用Promise

  1. Promise构造函数:Promise(executor){}

    • executor函数:执行器(resolve, reject) => {}
    • resolve函数:内部定义成功时我们调用的函数 value => {}
    • reject函数:内部定义失败时我们调用的函数 reason => {} executor会在Promise内部立即同步调用,异步操作在执行器中执行
      let p = new Promise( (resolve, reject) => {
        console.log('111');
      })
      console.log('222'); // 111 222
    
  2. Promise.prototype.then:(onResolved, onRejected) => {}

    • onResolved函数:成功的回调函数 (value) => {}
    • onRejected函数:失败的回调函数 (reason) => {} 指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象
  3. Promise.prototype.catch

  4. Promise.resolve(value) => {}

    • value:成功的数据或promise对象 说明:返回一个成功/失败的promise对象
      let p1 = Promise.resolve(20);
      // 如果传入的参数为非Promise类型的对象,则返回的结果为成功的promise对象
      // 如p2的Promise对象,则参数的结果决定了resolve的结果
      let p2 = Promise.resolve(new Promise((resolve, reject) => {
        resolve('ok');
      }))
      console.log(p2); // [PromiseState]:fulfilled [PromiseResult]: "ok"
    
  5. Promise.reject:(reason) => {}

    • reason:失败的原因 说明:返回一个失败的promise对象
      // 传任何东西都是失败 就算传入一个新的promise也是
      let p1 = Promise.reject(20);
      let p2 = Promise.reject('ee');
      console.log(p1); // [[PromiseState]]: "rejected" [[PromiseResult]]: 20
      console.log(p2); // [[PromiseState]]: "rejected" [[PromiseResult]]: "ee"
      
      let p3 = Promise.reject(new Promise((resolve, reject) => {
        resolve('ok')
      }))
      console.log(p3);
    
  6. Promise.all:(primises) => {}

    • promises:包含n个promise的数组 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败
      // 全部成功时
      let p1 = new Promise((resolve, reject) => {
        resolve('ok');
      })
      let p2 = Promise.resolve('success');
      let p3 = Promise.resolve('yes');
      const res = Promise.all([p1,p2,p3]);
      console.log(res); // [[PromiseState]]: "fulfilled"  [[PromiseResult]]: Array(3)
      
      // 含失败直接失败
      let p1 = new Promise((resolve, reject) => {
        resolve('ok');
      })
      let p2 = Promise.resolve('success');
      let p3 = Promise.reject('no');
      const res = Promise.all([p1,p2,p3]);
      console.log(res); // [[PromiseState]]: "rejected" [[PromiseResult]]: "no"
    
  7. Promise.race: (promises) => {}

    • promises:包含n个promise的数组 说明:返回一个新的primise,第一个完成的promise的结果状态就是最终的结果状态

promise的几个关键问题

  1. 如何改变promise的状态
  • resolve(value):如果当前是pending就会变为resolved
  • reject(reason):如果当前是pending就会变为rejected
  • 抛出异常:如果当前是pending就会变为rejected
  let p1 = new Promise((resolve, reject) => {
    // 1. resolve函数
    // resolve('ok'); // [[PromiseState]]: "fulfilled" [[PromiseResult]]: "ok" pending变fulfilled

    // 2. reject函数
    // reject('error') // [[PromiseState]]: "rejected" [[PromiseResult]]: "error" pending变rejected

    // 3. 抛出错误
    throw '出问题了' // [[PromiseState]]: "rejected" [[PromiseResult]]: "出问题了" pending变rejected
  })
  console.log(p1);
  1. 一个promise指定多个成功/失败回调函数,都会调用吗?
  • 当promise改变为对应状态时都会调用
 // resolve时
 let p1 = new Promise((resolve, reject) => {
   resolve('ok');
 })
 p1.then(value => {
   console.log(value); // 执行
 })
 p1.then(value => {
   alert(value);// 执行
 })
 console.log(p1);
 
 // reject时
 let p1 = new Promise((resolve, reject) => {
   reject('error');
 })
 p1.catch(value => {
   console.log(value); // 执行
 })
 p1.catch(value => {
   alert(value);// 执行
 })
 console.log(p1);
  1. 改变promise状态和指定回调函数谁先谁后?
  • 都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

  • 如何先改状态再指定回调?

    • 在执行器中直接调用resolve()/reject()
    • 延迟更长时间才调用then()
  • 什么时候才能得到数据?