用大白话讲懂async/await的基本用法和使用场景

async

async声明function是一个异步函数,返回一个promise对象,可以使用then方法添加回调函数。

1、async异步函数的执行流程

默认情况下和普通函数的执行流程是没什么区别的

js 复制代码
async function foo() {
    console.log("foo function start~")
    console.log("内部的代码执行1")
    console.log("foo function end~")
}

console.log("start")
foo()
console.log("end")

// 按顺序输出
// start
// foo function start~
// 内部的代码执行1
// foo function end~
// end

2、async异步函数的返回值

async函数的返回值一定为promise对象,promise对象的结果由async函数执行的返回值决定。

2.1、async函数返回值为promise对象

js 复制代码
async function foo() {}

// 异步函数的返回值一定是一个promise
console.log(foo()) // Promise { undefined }

2.1、async函数返回一个数字

js 复制代码
async function foo() {
    return 123
}

foo().then(res => {
    console.log(res) // 输出123
}).catch(err => {
    console.log(err)
})

2.2、async函数默认返回

js 复制代码
async function foo() {}

foo().then(res => {
    console.log(res) // 输出'undefined'
}).catch(err => {
    console.log(err)
})

2.2、async函数返回一个Promsie对象

js 复制代码
async function foo() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("hehehehe")
        }, 200)
    })
}

foo().then(res => {
    console.log(res) // 输出'hehehehe'
}).catch(err => {
    console.log(err)
})

await

await操作符只能在async异步函数内部使用。如果一个Promise被传递给一个await操作符,await将等待Promise 正常处理完成并返回其处理结果,也就是说它会阻塞后面的代码,等待 Promise对象结果。如果等待的不是Promise 对象,则返回该值本身。

1、await后面跟上一个数字

js 复制代码
async function foo() {
    const res1 = await 123
    console.log(res1) // 输出123
}
foo()

2、await后面跟上一个Promsie对象

只有当Promsie的状态变为Fulfilled,后面的代码才会执行。

js 复制代码
function requestData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('输出')
        }, 1000);
    })
}

async function foo() {
    // 如果没有结果,后面的代码是不会执行的,可以把上面的resolve注释掉试试
    const res1 = await requestData() 
    console.log(res1) // '输出'
    console.log("后面的代码1") // '后面的代码1'
}

foo()

3、await后面跟上reject值

如果await后面的异步操作出错,那么等同于async函数返回的 Promise对象被reject。后面的代码将不会再执行,我们可以使用try...catch进行包裹防止出错。

js 复制代码
function requestData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('输出')
        }, 1000);
    })
}

async function foo() {
    try {
        const res1 = await requestData() // 这里如果是reject 不会往后执行了
        console.log('后续代码')
    } catch (error) {

    }
}
foo()

async/await的使用场景

【超简单】一文搞懂Promise的使用一文中,我们谈到在真实的开发场景中,数据的请求一般是异步的,我们常常让接口返回一个Promise对象,以达到在依次请求每个接口的情况下,并保证数据依次输出。比如我现在有个需求:想依次请求接口1,接口2,接口3,并按顺序输出'我喜欢你'。

js 复制代码
function fn1() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('我')
        }, 1000)
    })
}

function fn2() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('喜欢')
        }, 200)
    })
}

function fn3() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('你')
        }, 100)
    })
}

fn1().then(res => {
    console.log(res)
    return fn2()
}).then(res => {
    console.log(res)
    return fn3()
}).then(res => {
    console.log(res)
})

// 1s后输出'我', 再过200ms后输出'喜欢',再过100ms后输出'你'

这么做是没问题的,但是如果嵌套的多了,不免有点不雅观,在开发中,为了代码的简洁性,我们也常用async/await来解决。

js 复制代码
async function getData() {
    let res1 = await fn1()
    console.log(res1)
    let res2 = await fn2()
    console.log(res2)
    let res3 = await fn3()
    console.log(res3)
}
getData()
// 1s后输出'我', 再过200ms后输出'喜欢',再过100ms后输出'你'

这样写还有以下好处:

1、更加灵活,直观地控制函数什么时候继续执行、暂停执行。 比如我现在有个需求,先请求完接口3,再拿接口3返回的数据,去当做接口4的请求参数。(在拿接口3的数据的后,我们可以做任何的处理,再拿最后的结果去作为接口4的请求参数,这个过程就相当于对函数进行了暂停,执行的操作)

js 复制代码
function fn4(val) {
    return new Promise(resolve => {
        setTimeout(() => {
            switch(val) {
                case 0:
                    resolve('我喜欢你')
                case 1:
                    resolve('你不喜欢我')
            }
        })
    })
}

async function getData() {
    let res1 = await fn3()
    res1 = res1 == '我' ? 0 : 1
    let res2 = await fn4(res1)
    console.log(res2)
}
getData()
// 输出'你不喜欢我'

2、等到所有的结果都有返回值后,才对所有的返回值进行处理。 比如我现在有个需求,我想拿到所有接口的数据,再对数据做一个总的输出。

js 复制代码
async function getData() {
    let res1 = await fn1()
    let res2 = await fn2()
    let res3 = await fn3()
    console.log(res1 + res2 + res3)
}
getData()
// 1.3s后输出'我喜欢你'

总结:

1、async函数返回的一定是一个Promise对象;

2、await只能在async函数中使用,不然会报错;

3、async/await的使用能使代码看起来更简洁;

4、async/await的使用更加灵活,直观地控制函数什么时候继续执行、暂停执行;

5、async/await的使用能更方便地等到所有的结果都有返回值后进行处理;

结语:

笔者写文章的目的主要还是想用简单的语言来讲懂某一个知识点,同时也巩固一下知识。如有错误的地方,还望大佬不吝赐教。如果觉得写得好的,也可以点个赞支持一下。

相关推荐
xxy-mm1 天前
Javascript 中的继承
开发语言·javascript·ecmascript
锋行天下1 天前
公司内网部署大模型的探索之路
前端·人工智能·后端
1024肥宅1 天前
手写 EventEmitter:深入理解发布订阅模式
前端·javascript·eventbus
海市公约1 天前
HTML网页开发从入门到精通:从标签到表单的完整指南
前端·ide·vscode·程序人生·架构·前端框架·html
3秒一个大1 天前
HTML5 与 JavaScript 中的二进制数据处理:ArrayBuffer 与 TextEncoder/Decoder 实践
javascript
purpleseashell_Lili1 天前
如何学习 AG-UI 和 CopilotKit
javascript·typescript·react
行云流水6261 天前
前端树形结构实现勾选,半勾选,取消勾选。
前端·算法
diudiu_331 天前
web漏洞--认证缺陷
java·前端·网络
阿珊和她的猫1 天前
<video>` 和 `<audio>` 标签的常用属性解析
前端
LSL666_1 天前
4 jQuery、JavaScript 作用域、闭包与 DOM 事件绑定
前端·javascript·html