【JS进阶】Promise/async await 详解

文章目录

  • Promise
    • 一、什么是Promise
    • 二、Promise初体验
    • 三、Promise 的状态改变
      • resolve不同值的区别
    • 四、Promise的实例方法
      • 1.then方法
        • then的参数
        • then的多次调用
        • then的返回值
      • 2.catch方法
        • catch的多次调用
        • catch的返回值
        • catch与then第二个参数的区别
      • 3.finally方法
    • 五、Promise中的类方法/静态方法
      • 1.Promise.reslove
      • 2.Promise.reject
      • 3.Promise.all
      • 4.Promise.allSettled
      • 5. Promise.race
      • 6.Promise.any
    • 六、async 与 await

Promise

一、什么是Promise

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

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

  • 解决了回调地狱的问题,以一种更线性的Promise链形式表达出来,更容易阅读和推断
  • 回调函数难以处理错误:Promise链提供了一种让错误正确传播的途径
  1. 抽象表达:
  1. Promise 是一门新的技术(ES6 规范)

  2. Promise 是 JS 中进行异步编程的新解决方案

备注:旧方案是单纯使用回调函数

  1. 具体表达:
  1. 语法上来说: Promise 是一个构造函数

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

二、Promise初体验

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

抽奖样例(Promise实现):

<body>
    <button onclick="draw()">点我抽奖button>
    <script>
        function rand(m,n){
            return Math.floor(Math.random()*n+m)
        }
       
        //按钮onclick事件的回调函数
        function draw(){
            //创建Promise对象,确定成功和失败的条件
            //resolve方法和reject方法会将Promise对象状态设置为【成功】和【失败】
            const p = new Promise((resolve,reject)=>{
                var result=rand(1,100);
                setTimeout(()=>{
                    if (result>=50) resolve(result);
                    else reject('badLuck')
                },1000)
            })

            //调用then方法,指定成功和失败之后的回调
            //then方法会根据Promise对象的状态来决定执行哪个函数
            p.then((value)=>{
                console.log('恭喜中奖!'+value);
            },(reason)=>{
                console.log('再接再厉!'+reason);
            })
        }

        
    script>
body>

三、Promise 的状态改变

  1. pending 变为 resolved
  2. 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的实例方法

1.then方法

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那它的状态如何决定呢?接下来让我们一探究竟。

  1. 返回一个普通值

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

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

  2. 返回一个Promise对象

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

2.catch方法

catch的多次调用

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

catch的返回值

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

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

catch与then第二个参数的区别

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

3.finally方法

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

五、Promise中的类方法/静态方法

1.Promise.reslove

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

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

2.Promise.reject

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

3.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都会把参数返回给我们

4.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没有结果,则什么都结果都拿不到

5. 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

6.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操作

你可能感兴趣的:(JS进阶,javascript,前端,vue.js)