ES6学习系列——async 函数

async 函数总览:

async 函数就是 Generator 函数的语法糖。

1、async 函数语法:

async 函数的常见使用形式:

//函数声明式
async function () {}

//函数表达式
let test = async function () {];
//还可以写成箭头函数: let test = async () => {};

//对象方法
let obj = { foo: async function () {}};

//写进class里面
class Test {
    constructor () { }
    async getTxt (url) {
        return await getText(url);
    }
}
let test = new Test();
test.getTxt ('/wamp/www/aaa.php').then(val => console.log(val));
//this is a async function test!
async 函数返回的是一个Promise 对象,return 出去的返回值就是then() 中回调函数的参数;
let getText = function (url) {
    let promise = new Promise((resolve, reject)=>{
        let xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.send(null);
        xhr.onreadystatechange = function () {
            if (xhr.readystate == 4) {
                if (xhr.status == 200) {
                    resolve(xhr.responseText);                  
                    throw new Error('test');
                }else{
                    reject(xhr.status);
                }
            }
        }       
    });
    return promise;
};

async function fn () {
    let text = await getText('/wamp/www/aaa.php');
    console.log(text); //text 内容是:this is a async function test!
    return text;    
}

fn().then((val)=>{
    console.log(val);
});
//this is a async function test!
因为async 函数返回的是一个Promise 对象,所以就要看看这个对象的状态的变化情况:

async 函数返回的Promise 对象的状态,由 async 内部所有的 await 命令后面跟着的 Promise 对象共同决定;
要么await 后面的所有promise 对象的状态确定为“成功”,async 函数状态随之确定为“成功”;
要么有一个 await 函数后面的Promise 对象状态确定为“失败”,async 函数状态随之确定为“失败”,然后async 函数中断执行(遇到return ,async 函数也会中断执行)。
换句话说,只有返回的Promise 对象状态确定下来,它才会执行 then() 方法中的回调函数;

2、await 命令的用法:

正常情况下,await 命令后面跟一个 Promise 对象,如果不是,引擎也会先用 Promise.resolve() 来转换一下,所以就不用我们瞎操心了;
await 后面跟着的 Promise 对象如果状态为“失败”,reject(reason)出去的 reason 会被 async 返回的Promise 对象的catch()方法捕抓到(当然你也可以将这个错误 给return 出去,如果不嫌多此一举的话)。

async function test () {
    await Promise.reject('Uncaught RangeError: Invalid array length');
    //也可以加上return
    //let err = await Promise.reject('Uncaught RangeError: Invalid array length');
    //return err;
} 
test().then(val => console.log(val))
      .catch(error => console.log(error));

上面已经提及,只要await 后面有一个Promise 对象的状态为“失败”,async 函数就会中断执行,如果想async 函数继续执行,应该怎么解决?
有两种方案:
第一种是利用try{ } catch(error){ }
第二种是直接给await 后面的Promise 对象加上catch()方法,处理出现的错误;

let test = async function () {
    try{
        await Promise.reject('出错啦,老哥');
        //这里还可以放多个await

    } catch (error) {
        console.log(error);
    }
    //第二种方案:
    //await Promise.reject('出错啦,老哥').catch(err => console.log(err));
    await Promise.resolve('hello world');
};
test().then(val => console.log(val));
//出错啦,老哥
//hello world
多提一句:如果多个 await 后面的异步操作没有一定的继发依赖,大可以将他们写成并发的,同时执行效率更高:
//比如
let foo = await foo();
let bar = await bar();

//上面的两个异步操作没有继发关系,就可以让他们一起执行啦,这样写:
let [foo, bar] = await Promise.all([foo(), bar()]);

3、async 函数实现原理探究:

利用Generator 函数 和 自动执行器 spawn 就可以实现 async 函数:

async function () {}

//equal to 

function () {
    return spawn (function* () {} );
}

下面就来看看 spawn() 自行执行器的具体原理:

function spawn (genFn) {
    // spawn 最后返回出去的是个 Promise 对象
    return new Promise ( (resolve, reject) => {         
        let gen = genFn(); // Generator 函数genFn() 返回的一个遍历器对象

        function nextFn () {
            return gen.next();
        }

        function step (nextFn) {
            try {
                let next = nextFn(); 
            } catch (e) {
                return reject(e);
            }

            if (next.done) {
                resolve(next.value);
            }

            Promise.resolve(next.value).then( (val) =>{
                step( () => return gen.next(val) );
            }, (e) => {
                step( () => return gen.next(e) );
            });     
        }
        step( () => return gen.next(undefined) );
    });
}

猜你喜欢

转载自blog.csdn.net/qq_39798135/article/details/82504451