es6之async函数

什么是async函数

async函数就是Generator函数的语法糖。async函数的实现原理就是Generator函数 + 自动执行器包装在一个函数里。es6

asycn函数 Generator函数
自带执行器 执行必须靠执行器
async/await语义清晰 星号和yield语义不明确
await命令后Promise对象和原型类型值 Thunk函数或Promise
返回值Promise,可使用then命令 返回值Iterator对象

怎么使用

aysnc函数返回一个Promise对象,aysnc函数内部return语句返回值,做为then方法回调函数的参数。当函数执行时候,一旦遇到await就会先返回,等到异步操做完成,再接着执行函数体内后面的语句。ajax

function sleep(ms) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, ms);
    });
}

async function foo(ms){
    await sleep(ms);
    return 300;
}

foo(2000).then((data)=> {
    console.log(data)
});
//300
复制代码

调用foo会当即返回一个promise,2s后await后面的promise状态变成resolve,才执行return,执行then,打印300。promise

因为async返回是promise,程序能够改成bash

async function sleep(ms) {
    await new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, ms);
    });
}
//...其余代码同上
复制代码

await命令后是一个Promise对象。若是不是,会被转成一个当即resolve的Promise。若是await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。能够参照es6之Promise深刻理解并发

let thenable = {
    then: (resolve) => {
        console.log('thenable');
        resolve('xxx');
    }
}
async function foo(){
    return await thenable;
}

foo().then((data)=> {
    console.log(data)
}).catch((e)=>{
    console.log(e.toString())
});

//thenable
//xxx
复制代码

错误处理机制

async函数内部抛出错误,外部catch捕获

内部抛出错误,后面语句不执行,直接外部catch捕获错误异步

async function foo(){
    throw new Error('出错了');
    await sleep(); //不执行
}

foo().then((data)=> {
    console.log(data)
}).catch((e)=>{
    console.log(e.toString())
});

//Error: 出错了
复制代码

这种状况会致使返回的Promise对象状态为reject状态,错误被catch方法回调函数接收到。async

async函数返回的Promise对象必须等到内部全部await命名后面的Promise对象执行完才会发生状态改变,除非遇到return语句或者抛出错误。函数

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

async函数内部抛出错误,内部catch捕获

内部本身捕获,程序继续往下执行return语句ui

async function foo(){
    await Promise.reject('error').catch((e)=>{
        console.log('in:', e.toString())
    });
    return 300;
}

foo().then((data)=> {
    console.log(data)
}).catch((e)=>{
    console.log('out:',e.toString())
});
//in: error
//300
复制代码

try...catch 实现屡次重复尝试

const NUM_RETRIES = 3;
async function multiRetries(url, count){
    let c = count || NUM_RETRIES;
    for(let i = 0; i < c; i++){
        try {
            await ajax.get(url);
            break; //请求成功就跳出循环
        } catch (error) {
            console.error(error);
        }
    }
}

multiRetries('http://xxxx').then((data)=> {
    console.log(data)
}).catch((e)=>{
    console.log(e.toString())
});
复制代码

注意点

多个await命令后面的异步操做,若是不存在继发关系,最好让他们同时触发

let [foo, bar] = await Promise.all([ajax.get(), ajax.post()])

//或
let fooPromise = ajax.get();
let barPromise = ajax.get();

let foo = await fooPromise;
let bar = await fooPromise;
复制代码

forEach中使用await中注意,以下是并发的。由于只有async函数内部是继发执行的,外部不受影响。

urls.forEach(async function(url){
    await ajax.get(url);
});

复制代码

异步遍历器

Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的 next 方法就会获得一个对象。特别注意 next 方法必须是同步的,只要调用就必须马上返回值。

Generator函数里面的异步操做返回一个Thunk函数或者Promise对象,等待之后返回真正的值,done属性仍是同步产生的。

for await ... of

async function foo(){
    try {
        for await (let value of createAsyncIterable()){
            console.log(value);
        }
    } catch (e) {
        console.log(e.toString());
    }
}
复制代码

异步Generator函数

await后面操做的应该返回Promise对象。使用yield关键字的地方,就是next方法停下来的地方。

async function* gen(){
    yield await Promise.resolve('xxx');
}
复制代码

注:读阮一峰老师的《ES6入门标准》作的笔记

相关文章
相关标签/搜索