深入解析Promise与async/await:用法、区别及实战案例

作者:拾光

时间:2026-10-25

浏览:376

本文详细对比了JavaScript中三种异步处理方式:回调函数、Promise和async/await。重点解析Promise的三种状态、常用方法及静态方法,并通过红绿灯示例展示其链式调用。同时阐述async/await作为Generator语法糖的原理,结合try-catch错误处理与React setState封装,提供清晰的异步编程最佳实践。

文章目录

一张直观的图表能够清晰展示回调函数(callback)、Promise以及async/await在代码使用层面的核心差异。

一、回调函数、Promise与async/await的核心区别

一、回调函数、Promise与async/await的核心区别

1. 回调函数(callback):深层嵌套会导致“回调地狱”,且需要手动检查错误参数(err)。

2. Promise:支持链式调用,可在then中直接返回新的Promise以处理成功回调,并通过catch集中处理错误。

3. async/await:将异步操作转化为同步风格的写法,既支持.catch方法,也兼容try-catch语法,代码简洁、可读性强且更优雅。

//try...catch
const fn = () => {
    return new Promise((resolve, reject) => {
        reject('你错啦~~')
    })
}
const asyncFn = async () => {
    try {
        let result1 = await fn()
    } catch (error) {
        console.log('try...catch:' + error)
    }
}
asyncFn()   //try...catch:你错啦~~
//catch
const asyncFn1 = async () => {
    const res = await fn().catch(err => console.log('catch:' + err))
}
asyncFn1()   //catch:你错啦~~

注意:try…catch能否捕获Promise抛出的异常?

答案是不能。try…catch主要用于捕获同步代码中抛出的异常,无法直接捕获异步Promise中的错误。

二、Promise详解

1. Promise的核心特点

1. 不可取消:Promise一旦创建便会立即执行,无法中途取消。

2. 错误静默:若未设置回调函数,Promise内部抛出的错误不会向外抛出。

3. 状态不可见:处于pending状态时,无法得知当前进展阶段(刚开始还是即将完成)。

2. Promise的基本用法

1. Promise的三种状态

  • pending: 进行中(Pending)
  • fulfilled: 已成功(Fulfilled)
  • rejected: 已失败(Rejected)

Promise构造函数接收两个参数:resolve(成功回调)和reject(失败回调)。

2. Promise原型链上的方法

  • then: 处理成功状态的回调
  • catch: 处理失败状态的回调
  • finally: 无论结果如何,执行完毕后都会触发的处理逻辑

3. Promise的静态方法

  • Promise.all():只要有一个Promise对象失败,整体即失败,并返回第一个失败的原因。
  • Promise.allSettled():不关心成功或失败,只等待所有Promise完成并返回结果。
  • Promise.any():返回第一个成功的Promise对象。
  • Promise.race():返回执行最快的那个Promise对象,无论其结果是成功还是失败。
  • Promise.resolve():返回一个状态为成功的Promise对象。
  • Promise.reject() :返回一个状态为失败的Promise对象。
let p1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 400, 'one');
});
let p2 = Promise.reject("two");
let p3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'three');
});
let p4 = Promise.resolve("four");
let p5 = new Promise((resolve, reject) => {
    // reject('reject');
    setTimeout(resolve, 500, 'five');
})
Promise.all([p1,p2,p3,p4,p5]).then(values => {
    console.log(values,"all"); 
}).catch((err) => {
    console.log(err,"allBad"); 
})

Promise.allSettled([p1,p2,p3,p4,p5]).then(values => {
    console.log(values,"allSettled"); 
}).catch((err) => {
    console.log(err,"allSettledBad"); 
})

Promise.any([p1,p2,p3,p4,p5]).then(values => {
    console.log(values,"any"); 
}).catch((err) => {
    console.log(err,"anyBad"); 
})

Promise.race([p1,p2,p3,p4,p5]).then(values => {
    console.log(values,"race"); 
}).catch((err) => {
    console.log(err,"raceBad"); 
})

3. Promise的实际应用(结合JS事件循环机制)

1. 场景:红灯亮3秒,绿灯亮1秒,黄灯亮2秒,如何交替重复亮灯?

function mylight(value,time){
    return new Promise((resolve,reject) => {
        setTimeout((params) => {
            console.log(value);
            resolve()
        },time)
    })
}

let step =()=>{
    Promise.resolve()
    .then(() => {
    //此处的return是为了执行后面的.then
        return mylight('red',3000)
    })
    .then((res) => {
        return mylight('green',1000)
    })
    .then((res) => {
        return mylight('yellow',2000)
    })
    .then(res=>{
      // 递归执行
       step()
    })
}
step()

扩展:如何利用reduce实现上述代码?了解reduce用法。

// 用reduce相当于往后面叠加.then,跟上面的重复亮灯代码一样
const arr = [
    {
        color:"red",
        time:3000,
    },
    {
        color:'green',
        time:1000,
    },
    {
        color:'yellow',
        time:2000
    }
]
function fn(arr) {
    arr.reduce((pre, cur,index) => {
        return pre.then(() => {
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(console.log(cur.color))
                }, cur.time)
            })
        })
    }, Promise.resolve()).then((params) => {
       fn(arr)
    })
    // 以上代码简写为:
    // arr.reduce((pre, cur) => pre.then(() => new Promise(r => setTimeout(() => r(console.log(cur.color)), cur.time))), Promise.resolve()).then((params) => fn(arr))
}
fn(arr)

三、async与await详解

1. async与await简介

async与await必须成对出现,其底层原理基于Generator函数。

async函数可视为Generator函数的语法糖,它将Generator的星号(*)替换为async,将yield替换为await,是对Generator封装的一套异步处理方案。

而Generator函数又依赖于迭代器(Iterator)。

迭代器(Iterator)的设计思想则来源于单向链表。

2. async和await的具体用法

1. 将异步操作转化为同步逻辑,从而获取最新的state值。

示例:使用Promise封装setState(异步编程场景)。

changeCount = (state)=>{
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
          this.setState(state)
        //resolve包裹成功时的结果
          resolve(this.state.count)
     },100)
   })
 },
pushRouter = async() => {
  //  await this.setState({
  //     count:this.state.count+1
  //   })
   const result = await this.changeCount({
   		count:this.state.count + 1
   })
}

2. async与await结合try-catch使用,以捕获异常。

async componentDidMount() {
   const { dispatch } = this.props
   try {
         const response = await dispatch({
              type: "netValueQuery/queryListData",
              payload: {}
         })
         if (response.httpStatus !== 200) {
             throw new Error(response.msg);
         }
         const json = await response.json();
         this.setState({ data: json });
       } catch (error) {
         console.log(error);
   }
}

3. 处理多个请求,后续请求需使用前面请求返回的值。

getSign(result){
    return this.$post(`/share/saveRecord`)
},
getTask() {
    const actid = this.$route.query.id;
    return this.$get(`/lottery/powerTask/${actid}`);
},
async getReady(){
    const task = await this.getTask()
    this.result = task.data.find(item => item.name.includes("分享"))
    const str = await this.getSign(this.result)
},

以上为个人经验总结,希望能给大家提供参考,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章