【JS】Promise/async await 详解

目录

Promise

promise是什么

Promise初体验

Promise 的状态改变

Promise的实例方法

then方法

then的多次调用

then的返回值

catch方法

catch的多次调用

catch的返回值

catch与then第二个参数的区别

finally方法

Promise中的类方法/静态方法

Promise.reslove

Promise.reject

Promise.all

Promise.allSettled

 Promise.race

Promise.any

async 与 await


Promise

promise是什么

Promise是处理异步问题的一种方式,之前都是用回调函数,如setTimeout( ( )=>{ } ,2000),

相对于传统的回调函数处理异步问题,Promise有以下几个好处:

解决了回调地狱的问题,以一种更线性的Promise链形式表达出来,更容易阅读和推断
回调函数难以处理错误:Promise链提供了一种让错误正确传播的途径

Promise 是一门新的技术(ES6 规范)

Promise 是 JS 中进行异步编程的新解决方案(备注:旧方案是单纯使用回调函数)

语法上来说: Promise 是一个构造函数

功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值

Promise初体验

Promise(承诺),给予调用者一个承诺,过一会返回数据给你,就可以创建一个promise对象
当我们new一个promise,此时我们需要传递一个回调函数,这个函数为立即执行的,称之为(executor)
这个回调函数,我们需要传入两个参数回调函数reslove,reject
当执行了reslove函数,会回调promise对象的.then函数
当执行了reject函数,会回调promise对象的.catche函数
抽奖样例(Promise实现):


    
    

Promise 的状态改变

pending 变为 resolved

pending 变为 rejected

【说明】:

只有这 2 种, 且一个 promise 对象只能改变一次

无论变为成功还是失败, 都会有一个结果数据

成功的结果数据一般称为 value, 失败的结果数据一般称为 reason,可以通过resolve和reject函数传递给then中方法。

Promise的函数参数是同步执行的,then方法是异步的!

 

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('失败')
    resolve('成功')
  }, 3000);
})

promise.then(res => console.log(res)).catch(err => console.log(err))

 resolve不同值的区别

  • 如果resolve传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为then回调的参数

 

const promise = new Promise((resolve, reject) => {
  resolve({name: 'ice', age: 22})
})

promise.then(res => console.log(res))

// {name: 'ice', age: 22}

 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态

const promise = new Promise((resolve, reject) => {
  resolve(new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('ice')
    }, 3000);
  }))
})

promise.then(res => console.log(res))

//3s后 ice
  • 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,then方法会传入resolvereject函数。此时的promise状态取决于你调用了resolve,还是reject函数。这种模式也称之为: thenable
const promise = new Promise((resolve, reject) => {
  resolve({
    then(res, rej) {
      res('hi ice')
    }
  })
})

promise.then(res => console.log(res))

// hi ice

Promise的实例方法

then方法

then方法可以接受参数,一个参数为成功的回调,另一个参数为失败的回调

const promise = new Promise((resolve, reject) => {
  resolve('request success')
  // reject('request error')
})

promise.then(res => console.log(res), rej => console.log(rej))

//request success
then的多次调用

then的多次调用则会执行多次

const promise = new Promise((resolve, reject) => {
  resolve('hi ice')
})

promise.then(res => console.log(res))
promise.then(res => console.log(res))
promise.then(res => console.log(res))

//hi ice
//hi ice
//hi ice
then的返回值

then方法是有返回值的,它的返回值是promise

但是是promise那它的状态如何决定呢?接下来让我们一探究竟。

  • 返回一个普通值

则相当于主动调用Promise.resolve,并且把返回值作为实参传递到then方法中

如果没有返回值,则相当于返回undefined

  • 返回一个Promise对象

那么取决于返回的这个Promise对象的状态


catch方法

catch的多次调用

同.then方法,也会执行多次

catch的返回值

catch方法也是有返回值的,返回的也是一个Promise对象,而且这个Promise对象的状态确定方法与then方法完全一致。

catch与then第二个参数的区别

catch是用来处理异常的,那么catch与.then方法的第二个回调函数有什么区别呢?

主要区别就是:如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。

finally方法

  • ES9(2018)新实例方法
  • finally(最后),无论promise状态是fulfilled还是rejected都会执行一次finally方法

Promise中的类方法/静态方法

Promise.reslove

Promise.resolve('ice')
//等价于
new Promise((resolve, reject) => resolve('ice'))

有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式

Promise.reject

类似地,可以得到一个状态为rejected的Promise对象

Promise.all

  • all方法的参数传入为一个可迭代对象,返回一个promise,只有三个都为resolve状态的时候才会调用.then方法。
  • 只要有一个promise的状态为rejected,则会回调.catch方法
let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

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

let p3 = Promise.reject('失败')

Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})
  • 当遇到rejectd的时候,后续的promise结果我们是获取不到,并且会把reject的实参,传递给catch的err形参中

上面的Promise.all有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve或者reject的结果我们是拿不到的,因此ES11 新增语法Promise.allSettled,无论状态是fulfilled/rejected都会把参数返回给我们

Promise.allSettled

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('hi ice')
  }, 1000);
})

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('hi panda')
  }, 2000);
})

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('hi grizzly')
  }, 3000);
})

Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))

/* [
  { status: 'rejected', reason: 'hi ice' },
  { status: 'fulfilled', value: 'hi panda' },
  { status: 'rejected', reason: 'hi grizzly' }
] */

 Promise.race

  • 优先获取第一个返回的结果,无论结果是fulfilled还是rejectd
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('hi error')
  }, 1000);
})

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('hi panda')
  }, 2000);
})


Promise.race([promise1, promise2])
       .then(res => console.log(res))
       .catch(e => console.log(e))
       
//hi error

Promise.any

  • 与race类似,但是只获取第一个状态为fulfilled,如果全部为rejected则报错AggregateError

async 与 await

异步函数(async function)中可以使用await关键字,普通函数不行

  • 通常await关键字后面都是跟一个Promise

    • 可以是普通值
    • 可以是thenable
    • 可以是Promise主动调用resolve或者reject
  • 这个promise状态变为fulfilled才会执行await后续的代码,所以await后面的代码,相当于包括在.then方法的回调中,如果状态变为rejected,你则需要在函数内部try catch,或者进行链式调用进行.catch操作

你可能感兴趣的:(javascript,前端,开发语言)