与Promise血脉相连的async/await

async/await是JavaScript为了解决异步问题而提出的一种解决方案,许多人将其称为异步的终极解决方案。JavaScript的发展也经历了回调、Promise、async/await三个阶段,本篇文章记录了我本身对于async/await的理解。由于async/await的使用离不开Promise,若是对于Promise不熟悉的话,能够看下这篇介绍:前端萌新眼中的Promise及使用前端

1、async/await的具体使用规则

在咱们处理异步的时候,比起回调函数,Promise的then方法会显得较为简洁和清晰,可是在处理多个彼此之间相互依赖的请求的时候,就会显的有些累赘。这时候,用async和await更加优雅,后面会详情说明。程序员

async/await使用规则一:凡是在前面添加了async的函数在执行后都会自动返回一个Promise对象编程

例子:promise

async function test() {
    
}

let result = test()
console.log(result)  //即使代码里test函数什么都没返回,咱们依然打出了Promise对象
复制代码

async/await使用规则二:await必须在async函数里使用,不能单独使用bash

错误的例子:dom

function test() {
    let result = await Promise.resolve('success')
    console.log(result)
}

test()   //执行之后会报错
复制代码

正确的例子:异步

async test() {
    let result = await Promise.resolve('success')
    console.log(result)
}
test()
复制代码

async/await使用规则三:await后面须要跟Promise对象,否则就没有意义,并且await后面的Promise对象没必要写then,由于await的做用之一就是获取后面Promise对象成功状态传递出来的参数。async

正确的例子:函数

function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        })
    })
}

async test() {
    let result = await fn() //由于fn会返回一个Promise对象
    console.log(result)    //这里会打出Promise成功后传递过来的'success'
}

test()
复制代码

没有意义的例子(不会报错):post

async test() {
    let result = await 123
    console.log(result)
}

test()
复制代码

2、async/await的错误处理方式

关于错误处理,如规则三所说,await能够直接获取到后面Promise成功状态传递的参数,可是却捕捉不到失败状态。在这里,咱们经过给包裹await的async函数添加then/catch方法来解决,由于根据规则一,async函数自己就会返回一个Promise对象。

一个包含错误处理的完整的async/await例子:

let promiseDemo = new Promise((resolve, reject) => {
    setTimeout(() => {
        let random = Math.random()
        if (random >= 0.5) {
            resolve('success')
        } else {
            reject('failed')
        }   
    }, 1000)
})

async function test() {
    let result = await promiseDemo
    return result  //这里的result是promiseDemo成功状态的值,若是失败了,代码就直接跳到下面的catch了
}

test().then(response => {
    console.log(response) 
}).catch(error => {
    console.log(error)
})

复制代码

上面的代码须要注意两个地方,一是async函数须要主动return一下,若是Promise的状态是成功的,那么return的这个值就会被下面的then方法捕捉到;二是,若是async函数有任何错误,都被catch捕捉到!

3、同步与异步

在async函数中使用await,那么await这里的代码就会变成同步的了,意思就是说只有等await后面的Promise执行完成获得结果才会继续下去,await就是等待,这样虽然避免了异步,可是它也会阻塞代码,因此使用的时候要考虑周全。

好比下面的代码:

function fn(name) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(`${name}成功`)
        }, 1000)
    })
}

async function test() {
    let p1 = await fn('小红')
    let p2 = await fn('小明')
    let p3 = await fn('小华')
    return [p1, p2, p3]
}

test().then(result => {
    console.log(result)
}).catch(result => {
    console.log(result)
})
复制代码

这样写虽然是能够的,可是这里await会阻塞代码,每一个await都必须等后面的fn()执行完成才会执行下一行代码,因此test函数执行须要3秒。若是不是遇到特定的场景,最好仍是不要这样用。

3、一个小测试

写到这里,忽然想起Promise的代码执行顺序也是挺须要注意的。

请看下面的代码,执行完之后打出的数字的顺序是怎样的呢?

console.log(1)
let promiseDemo = new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => {
        let random = Math.random()
        if (random >= 0.2) {
            resolve('success')
            console.log(3)
        } else {
            reject('failed')
            console.log(3)
        }   
    }, 1000)
})

async function test() {
    console.log(4)
    let result = await promiseDemo
    return result
}

test().then(result => {
    console.log(5)
}).catch((result) => {
    console.log(5)
})

console.log(6)
复制代码

答案是:1 2 4 6 3 5

4、一个适合使用async/await的业务场景

在前端编程中,咱们偶尔会遇到这样一个场景:咱们须要发送多个请求,而后面请求的发送老是须要依赖上一个请求返回的数据。对于这个问题,咱们既能够用的Promise的链式调用来解决,也能够用async/await来解决,然然后者会更简洁些。

使用Promise链式调用来处理:

function request(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

request(500).then(result => {
    return request(result + 1000)
}).then(result => {
    return request(result + 1000)
}).then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
}) 
复制代码

使用async/await的来处理:

function request(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

async function getResult() {
    let p1 = await request(500)
    let p2 = await request(p1 + 1000)
    let p3 = await request(p2 + 1000)
    return p3
}

getResult().then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})
复制代码

相对于使用then不停地进行链式调用, 使用async/await会显的更加易读一些。

5、在循环中使用await

若是在是循环中使用await,就须要牢记一条:必须在async函数中使用

for...of中使用await:

let request = (time) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}

let times = [1000, 500, 2000]
async function test() {
    let result = []
    for (let item of times) {
        let temp = await request(item)
        result.push(temp)
    }
    return result
}

test().then(result => {
    console.log(result)
}).catch(error => {
    console.log(error)
})
复制代码

上面就是我今天关于async/await理解的记录,笔者做为一只程序员生活只有半年,以上内容估计还有错误之处,若是掘金上的朋友有看到,还望不吝指出!谢谢您的观看!

相关文章
相关标签/搜索