Administrator
发布于 2025-11-22 / 4 阅读
0

异步处理

1. Promise Async

同步和异步

同步任务执行特点就是按顺序一个一个往下执行

如果中间加了类似settimeout定时器,他会带着后续的任务一起延迟,我们不希望后续任务被延迟,就产生了异步

常见的异步任务有两种:定时器和Ajax

异步任务创建之后不会像同步任务一样按顺序执行,而是在特殊队列里等待,然后通过一定的机制,添加到主线程中执行

        console.log('任务1:...同步')
        console.log('任务2:...同步')
        setTimeout(() => {
            console.log('任务3:....异步')
        }, 0)
        console.log('任务4:...同步')

这里可以看到,虽然时间设为0,但是setTimeout触发的异步任务内部的代码不会在它本来的位置执行

所以,异步任务可以理解为,他会在当前所有同步任务都执行完了之后再触发,和时间没关系

如果任务4需要依赖任务3处理的结果,这时就不能这么写了,应该把任务4也放到setTimeout里

        console.log('任务1:...同步')
        console.log('任务2:...同步')
        setTimeout(() => {
            console.log('任务3:...异步')
            console.log('任务4:...同步')
        }, 0)

但是如果代码中有大量的异步任务参与程序执行,就会让代码出现大量嵌套层数

        console.log('任务1:...同步')
        console.log('任务2:...同步')
        setTimeout(() => {
            console.log('任务3:....异步')
            console.log('任务4:...同步')
            setTimeout(() => {
                console.log('任务3:....异步')
                console.log('任务4:...同步')
                setTimeout(() => {
                    console.log('任务3:....异步')
                    console.log('任务4:...同步')
                }, 0)
            }, 0)
        }, 0)

就像这样,代码复杂程度大大提升,也没啥可读性

为了解决这个问题,产生了promise,用来解决异步写法中嵌套问腿

        const p1 = new Promise((resolve, reject) => {
            resolve('任务成功的结果')
            // reject('任务失败的结果')
        })
        p1.then(data => {
            console.log(data)
        })
            .catch(err => {
                console.log(err)
            })

来分析一下这个代码,promise接收一个参数,这个参数是一个函数,而在这个函数里又接收两个形参

resolve和reject,resolve是成功时候的工具,而reject则是失败时候的工具

promise的实例对象具备三个方法,比较常用的是then和catch

then就是接下来做什么,在then里也可以接收一个回调函数,参数叫data,表示在成功的时候给我们传递的一个成功数据,也就是当promise里面是resolve时可以在里面传递信息,then就会被触发;比如说promise里是resolve时,then就会被触发,data接收resolve里的数据,然后执行

.catch就和then相反,它被reject触发,可以接收一个参数err,当promise里面是reject时,catch会被触发,err接收reject里的数据(里面可以写错误信息),然后执行(catch其实是reject的兜底操作,如果不写这个catch,当promise里是reject时,直接是报错,就像下图)

但是这也没解决嵌套问题啊?

其实可以在then里面再return new Promise

        const p1 = new Promise((resolve, reject) => {
            resolve('任务1成功的结果')
            // reject('任务失败的结果')
        })
        p1.then(data => {
            console.log(data)
            return new Promise((resolve, reject) => {
                resolve('任务2成功的结果')
            })
        })
            .then(data => {
                console.log(data)
            })
            .catch(err => {
                console.log(err)
            })

其实可以这么理解,第一个任务执行成功之后,执行结果交给了第一个then,这时在第一个then里面再次return一个Promise,里面是第二个任务,这样return的执行结果会被下一个then接收,以此类推,就变成了执行完第一个执行第二个....但是中间也不会又太多嵌套,最多一层

如果想要让每个任务如果失败返回不一样的结果的话,就可以在每个then后面都加一个失败处理

先来一个错误案例

        const p1 = new Promise((resolve, reject) => {
            // resolve('任务1成功的结果')
            reject('任务1失败的结果')
        })
        p1.then(data => {
            console.log(data)
            return new Promise((resolve, reject) => {
                resolve('任务1成功的结果')
            })
        }, err => {
            console.log('任务1失败了')
        })
            .then(data => {
                console.log(data)
            }, err => {
                console.log('任务2失败了')
            })

就像这样,但是问题来了

任务1失败了,那任务2不应该也提示失败吗?为什么是undefined?

这个问题其实是在进行失败设置的时候,失败应该返回一个值,如果没有设置返回值,默认就会返回一个成功的promise对象,导致后续的then会被触发,但是接不到数据

这种问题又两种改法,一个是在err里返回一个新的Promise,这个Promise是一个失败状态;二是再err里抛出一个异常throw new Error( ),后面的看到前面已经失败了,后面的也就不干了

        const p1 = new Promise((resolve, reject) => {
            // resolve('任务1成功的结果')
            reject('任务1失败的结果')
        })
        p1.then(data => {
            console.log(data)
            return new Promise((resolve, reject) => {
                resolve('任务1成功的结果')
            })
        }, err => {
            console.log('任务1失败了')
            throw new Error('任务1失败')
        })
            .then(data => {
                console.log(data)
            }, err => {
                console.log('任务2失败了')
            })

这样其实就可以解决最开始层层嵌套的问题

        const p1 = new Promise((resolve, reject) => {
            resolve('阶段1执行成功')
            //reject('任务1执行失败')
        })
        p1.then(data => {
            console.log('任务1:...')
            console.log('任务2:...')
            console.log(data)
            return new Promise((resolve, reject) => {
                // resolve('阶段2执行成功')
                reject('阶段2执行失败')
            })
        }, err => {
            throw new Error('阶段1执行失败')
        })
            .then(data => {
                console.log('任务3:...')
                console.log('任务4:...')
                console.log(data)
                return new Promise((resolve, reject) => {
                    resolve('阶段3执行成功')
                    // reject('阶段3执行失败')
                })
            }, err => {
                console.log(err)
                throw new Error('阶段2执行失败')
            })
            .then(data => {
                console.log('任务5:...')
                console.log('任务6:...')
                console.log(data)
            }, err => {
                console.log('阶段3执行失败')
            })

2. Async await

Async await就是基于Promise的语法糖,目的是用”看起来像同步的代码"去写异步的逻辑

先看Async,函数前面加上async后,就变成了异步函数,他有两个特点

1.返回值一定是一个Promise

2.赞函数内部可以使用await

先来看第一个特点

async function fn() {
  return 123
}

const p = fn()
console.log(p)

这段代码和下面这段一样

function foo() {
  return Promise.resolve(123)
}

在看第二个特点之前先了解什么是await

await只能在async函数里用,作用是等待一个prmise完成并且拿到他的结果

先来看这一段

        function asyncTask() {
            return new Promise((resolve, reject) => {
                //假装有一些关键代码
                const isSuccess = true
                if (isSuccess) {
                    resolve('任务1:....成功的处理结果')
                } else {
                    reject('任务1:...失败的处理结果')
                }
            })
        }
        async function main() {
            console.log('任务1')
            const data = await asyncTask()
            console.log(data)
            console.log('任务3')
        }
        main()

可以看到他可以和同步操作一样,看起来没有区别,但实际上是异步操作逻辑

function stage1() {
  return Promise.resolve('阶段1执行成功')
}

function stage2() {
  return Promise.reject('阶段2执行失败')
}

function stage3() {
  return Promise.resolve('阶段3执行成功')
}

async function run() {
  try {
    // 阶段1
    const data1 = await stage1()
    console.log('任务1:...')
    console.log('任务2:...')
    console.log(data1)

    // 阶段2
    const data2 = await stage2()
    console.log('任务3:...')
    console.log('任务4:...')
    console.log(data2)

    // 阶段3
    const data3 = await stage3()
    console.log('任务5:...')
    console.log('任务6:...')
    console.log(data3)
  } catch (err) {
    console.log('出错了:', err)
  }
}

run()

可以看到,它的错误处理是配合try...catch进行书写

在实际开发中,async await最常用的就是请求接口

import axios from 'axios'

async function getArticles() {
  try {
    const res = await axios.get('/api/articles')
    console.log('文章列表:', res.data)
  } catch (err) {
    console.log('请求失败:', err)
  }
}

getArticles()

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // console.log('任务1:...同步')
        // console.log('任务2:...同步')
        // setTimeout(() => {
        //     console.log('任务3:....异步')
        //     console.log('任务4:...同步')
        // }, 0)

        // const p1 = new Promise((resolve, reject) => {
        //     // resolve('任务1成功的结果')
        //     reject('任务1失败的结果')
        // })
        // p1.then(data => {
        //     console.log(data)
        //     return new Promise((resolve, reject) => {
        //         resolve('任务1成功的结果')
        //     })
        // }, err => {
        //     console.log('任务1失败了')
        //     throw new Error('任务1失败')
        // })
        //     .then(data => {
        //         console.log(data)
        //     }, err => {
        //         console.log('任务2失败了')
        //     })

        //     const p1 = new Promise((resolve, reject) => {
        //         resolve('阶段1执行成功')
        //         //reject('任务1执行失败')
        //     })
        //     p1.then(data => {
        //         console.log('任务1:...')
        //         console.log('任务2:...')
        //         console.log(data)
        //         return new Promise((resolve, reject) => {
        //             // resolve('阶段2执行成功')
        //             reject('阶段2执行失败')
        //         })
        //     }, err => {
        //         throw new Error('阶段1执行失败')
        //     })
        //         .then(data => {
        //             console.log('任务3:...')
        //             console.log('任务4:...')
        //             console.log(data)
        //             return new Promise((resolve, reject) => {
        //                 resolve('阶段3执行成功')
        //                 // reject('阶段3执行失败')
        //             })
        //         }, err => {
        //             console.log(err)
        //             throw new Error('阶段2执行失败')
        //         })
        //         .then(data => {
        //             console.log('任务5:...')
        //             console.log('任务6:...')
        //             console.log(data)
        //         }, err => {
        //             console.log('阶段3执行失败')
        //         })

        function asyncTask() {
            return new Promise((resolve, reject) => {
                //假装有一些关键代码
                const isSuccess = true
                if (isSuccess) {
                    resolve('任务2:....成功的处理结果')
                } else {
                    reject('任务2:...失败的处理结果')
                }
            })
        }
        async function main() {
            console.log('任务1')
            const data = await asyncTask()
            console.log(data)
            console.log('任务3')
        }
        main()

        // async function foo() {
        //     return 123
        // }

        // const p = foo()
        // console.log(p)

    </script>
</body>

</html>