ES6之async await

含义

  • 内置执行器
    • Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行fn()
  • 更好的语义
    • async和await,比起星号和yield,语义更清除了。async表示函数里又异步操作,await表示紧跟在后面的表达式需要等待结果。
  • 更广的适用性
    • co模块规定,yield命令后面只能时Thunk函数或Promise对象,而async函数的await命令后面,可不是Promise对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即resolved 的Promise对象)
  • 返回值时Promise
    • async函数的返回值时Promise对象,这比Generator函数的返回值是Iterator对象方便多了。你可以用then方法制定下一步操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是then方法的语法糖

基本用法

async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,在接着执行函数体后面的语句

    async function fn(){
        console.log(4)
        let f1 = await Promise.resolve(1)
        console.log(f1) // 1
        let f2 = await Promise.resolve(2)
        return f2
    }
    fn().then(res=>{
        console.log(res) // 2
    })
    console.log(3)
    // 4  3  1  2

上面代码中,函数前面的async关键字,表示函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。

    function timeout(ms){
        return new Promise((resolve)=>{
            setTimeout(resolve,ms)
        })
    }
    async function fn(value,ms){
        await timeout(ms)
        console.log(value)
    }
    fn('haha',3000)

上面代码会在3秒后输出haha

async函数有多种使用形式。

    // 函数声明
    async function fn(){}
    // 函数表达式
    let fn1 = async function(){}
    // 对象的方法
    let obj = {async foo(){}}
    obj.foo().then(()=>console.log(111)) // 111
    // class 的方法
    class fn2{
        constructor(name){
            this.name = name;
        }
        async getName(){
            return this.name
        }
    }
    let name = new fn2('小明');
    name.getName().then(res=>console.log(res)) // 小明

语法

async函数返回一个Pormise对象。
async函数内部return语句返回的值,会成为then方法回调函数的参数

    let fn = async function(){
        return 111
    }
    fn().then(res=>{console.log(res)}) // 111

上面代码,函数fn返回的值,会被then放回回调函数接收到

async内部抛出错误,会导致返回的Promise对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

    let fn = async function(){
        throw new Error('出错了')
    }
    fn().catch(error=>{
        console.log(error); // Error: 出错了
    })
Promise对象的状态变化

async函数返回的Promise对象,碧玺等到内部所有await命令后面的Promise对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有asunc函数内部的异步操作执行完,才会执行then方法指定的回调函数。

    let fn = async function(){
        await new Promise((resolve)=>{
            setTimeout(resolve,3000)
        })
        await new Promise((resolve)=>{
            setTimeout(resolve,3000)
        })
        return 1
    }
    fn().then(res=>{
        console.log(res);
    })

上面代码,then回调函数会在6秒之后输出res

await

正常情况下,await命令后面是一个Promise对象,返回该对象的结果。如果不是Promise对象,就直接返回对应的值

    let fn = async function(){
        // 等同于
        // return 1
        return await 1
    }
    fn().then(res=>{
        console.log(res); // 1
    })

上面代码中,await命令的参数是数值1,这是等同于return 1

    let fn = async ()=>{
        await Promise.reject('出错了')
    }
    fn().catch(error=>{console.log(error)}) // 出错了

注意:上面代码中,await语句前面没有return,但是reject方法的参数依然传入了catch方法的回调函数。这里如果在await前面加上return,效果是一样的

注意:任何一个await语句后面的Promise对象变为reject,那么整个async函数都会中断执行

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行

    let fn = async ()=>{
        try{
            await Promise.reject('出错了')
        }catch(error){
            console.log(error) 
        }
        return 1
    }
    fn().then(res=>console.log(res)) // 1

另一种写法

    let fn = async ()=>{
        await Promise.reject('出错了').catch(error=>{
            console.log(error) 
        })
        return 1
    }
    fn().then(res=>console.log(res)) // 1

错误处理

如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。

    let fn = async ()=>{
        await Promise.reject('出错了')
        return 1
    }
    fn()
    .then(res=>console.log(res))
    .catch(error=>{
        console.log(error) // 出错了
    })

上面代码中,函数fn执行后,await后面的Promise对象抛出了一个错误对象,导致catca方法的回调函数被调用。

防止出错的方法,也是将其放在try...catch代码块中

    let fn = async ()=>{
        try{
            await Promise.reject('出错了')
        }catch(error){
            console.log(error);
        }
        return 1
    }
    fn()
    .then(res=>console.log(res)) // 1

如果有多个await命令,可以统一放在try...catch

posted @ 2019-05-08 19:57  我会放电啪啪  阅读(1188)  评论(0编辑  收藏  举报