JavaScript Promise

30 阅读4分钟

Promise

Promise是一套专门处理异步场景的规范,它能有效的避免回调地狱的产生,使异步代码更加清晰、简洁、统一

  • 所有的异步场景,都可以看作是一个异步任务,每个异步任务,在JS中应该表现为一个对象,该对象称之为Promise对象,也叫做任务对象 image-20210618154556558

  • 每个任务对象,都应该有两个阶段、三个状态 image-20210618155145355

    根据常理,它们之间存在以下逻辑:

    • 任务总是从未决阶段变到已决阶段,无法逆行
    • 任务总是从挂起状态变到完成或失败状态,无法逆行
    • 时间不能倒流,历史不可改写,任务一旦完成或失败,状态就固定下来,永远无法改变
  • 挂起->完成,称之为 resolve挂起->失败称之为 reject。任务完成时,可能有一个相关数据;任务失败时,可能有一个失败原因。 image-20210618160538875

  • 可以针对任务进行后续处理,针对完成状态的后续处理称之为onFulfilled,针对失败的后续处理称之为onRejected image-20210618161125894

    image-20210618161125894

catch方法

.catch(onRejected) = .then(null, onRejected)

链式调用

image-20210621103501094

  1. then方法必定会返回一个新的Promise

    可理解为 后续处理也是一个任务

  2. 新任务的状态取决于后续处理:

    • 若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据

    触发reject(),但是没有相关的catchthen处理,那么这个后续处理函数的状态是rejected

    • 若有后续处理但还未执行,新任务挂起。

    rejectresolve 都未触发,后面的任务处于pending状态

    若后续处理执行了,则根据后续处理的情况确定新任务的状态

    1. 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值

      后续处理是catch,如果无错,返回的新任务状态是fulfilled

    2. 后续处理执行有错,新任务的状态为失败,数据为异常对象

    如果catch 或者then处理函数执行有误,返回任务就是rejected

    1. 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致

    如果catch then 返回的是一个任务对象,也就是新的promise,状态就是该任务

Promise的静态方法

方法名含义
Promise.resolve(data)直接返回一个完成状态的任务
Promise.reject(reason)直接返回一个拒绝状态的任务
Promise.all(任务数组)返回一个任务
任务数组全部成功则成功
任何一个失败则失败
Promise.any(任务数组)返回一个任务
任务数组任一成功则成功
任务全部失败则失败
Promise.allSettled(任务数组)返回一个任务
任务数组全部已决则成功
该任务不会失败
Promise.race(任务数组)返回一个任务
任务数组任一已决则已决,状态和其一致

例子

image.png

消除回调

有了Promise,异步任务就有了一种统一的处理方式

有了统一的处理方式,ES官方就可以对其进一步优化

ES7推出了两个关键字asyncawait,用于更加优雅的表达Promise

async

async关键字用于修饰函数,被它修饰的函数,一定返回Promise

async function method1(){
  return 1; // 该函数的返回值是Promise完成后的数据
}

method1(); // Promise { 1 }

async function method2(){
  return Promise.resolve(1); // 若返回的是Promise,则method得到的Promise状态和其一致
}

method2(); // Promise { 1 }

async function method3(){
  throw new Error(1); // 若执行过程报错,则任务是rejected
}

method3(); // Promise { <rejected> Error(1) }

await

await关键字表示等待某个Promise完成,它必须用于async函数中

async function method(){
  const n = await Promise.resolve(1);
  console.log(n); // 1
}

// 上面的函数等同于
function method(){
  return new Promise((resolve, reject)=>{
    Promise.resolve(1).then(n=>{
      console.log(n);
      resolve(1)
    })
  })
}

await也可以等待其他数据

async function method(){
  const n = await 1; // 等同于 await Promise.resolve(1)
}

如果需要针对失败的任务进行处理,可以使用try-catch语法

async function method(){
  try{
    const n = await Promise.reject(123); // 这句代码将抛出异常
    console.log('成功', n)
  }
  catch(err){
    console.log('失败', err)
  }
}

method(); // 输出: 失败 123