用大白话讲懂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的使用能更方便地等到所有的结果都有返回值后进行处理;

结语:

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

相关推荐
小镇程序员3 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐5 分钟前
前端图像处理(一)
前端
程序猿阿伟12 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒14 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪22 分钟前
AJAX的基本使用
前端·javascript·ajax
力透键背25 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M36 分钟前
node.js第三方Express 框架
前端·javascript·node.js·express
weiabc36 分钟前
学习electron
javascript·学习·electron
盛夏绽放44 分钟前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
想自律的露西西★1 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5