async函数

  • Generator函数的语法糖
  • async函数必须等到内部所有的await执行完才会执行then方法制定的回调函数

  • async对于generator的改进方面:

    • 内置执行器(async不用调用next方法执行)
    • 更好的语义(async表示内部有异步操作;await表示紧随后面的表达式需要等待结果)
    • 适用更加广泛

      • yield后面只能是thunk函数或者Promise对象
      • async函数的await后面可以使Promise对象和原始类型的值(数值、字符串、布尔值,但是这时候会自动转换成曾立即resolved的Promise对象)
    • 返回值

      • yield返回值是Iterator对象
      • async函数返回值是Promise对象
  • async函数可以看做欧式多个异步函数包装成的一个Promise对象,await命令就是内部then命令的语法糖

基本用法

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

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

async function asyncPrint(value,ms){
    await timeout(ms);
    console.log(value)
}
asyncPrint('hello world',500)

注意:上面代码在50ms后输出hello world

由于async的返回是Promise对象,可以作为await的命令函数,那么上面代码也可以写成

async function timeout(ms){
    await new Promise((resolve)=>{
        setTimeout(resolve,ms)
    })
}
async function asyncPrint(value,ms){
    await timeout(ms);
    console.log(value)
}
asyncPrint('hello world',500)

async函数多种使用形式

  • 函数声明

    async function foo(){}
    
  • 函数表达式

    const foo = async function(){}
    
  • 对象的方法

    let obj = {async foo(){}};
    obj.foo().then(...)
    
  • Class的方法

    class Storage{
        constructor(){
            this.cachePromise = caches.open('avatars');
        }
        async getAvatar(name){
            const cache = await this.cachePromise;
            return cache.match(`/avatars/${name}.jpg`)
        }
    }
    const storage = new Storage();
    storage.getAvartar('smileyqp').then(...)
    
  • 箭头函数

    const foo = async() => {}
    
    async function f(){
        return 'hello world'
    }
    

await

  • await命令后面是一个Promise对象,返回该对象的结果,如果不是Promise对象,就直接返回对应的值
async function f(){
    return await 123;    //等同于 return 123;
}
f().then((v)=>{    console.log(v)})
//123
  • await实现休眠效果

    function sleep(interval){
        return new Promise(resolve => {
            setTimeout(resolve,interval)
        })
    }
    async function testInterval(){
        for(let i =1;i <= 5;i++){
            console.log(i);
            await sleep(1000)
        }
    }
    testInterval();
    

错误处理

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

  • 利用try catch
  • 利用catch方法的回调

多个异步操作,如果不存在继发关系,最好让他们同时触发

let foo = await getFoo();
let bar = await getBar();

注意:上面代码中getFoo和getBar是两个独立的操作,被写成相继关系,这样比较耗时,因为只有当上面的完成之后才会执行下面的getBar;我们完全可以让他们同时出发

//写法一
let [foo,bar] = await Promise.all([getFoo(),getBar()]);

//写法二:
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bat = await barPromise;

await只能用在async方法中

async function func(db){
    let docs = [{},{},{}];

    docs.forEach(function(doc){
        await db.post(doc);            //await用在普通方法中报错
    })
}

注意:将上面的里面的function前面加上async改成异步也会报错;因为那样的话几个db.post是并发执行,即同步执行并不是继发执行的;正确写法是改成for循环

async function func(db){
    let docs = [{},{},{}];

    dor(let doc of docs){
        await db.post(doc)
    }
}

如果确实希望几个请求并发执行,可以使用Promise.all方法

//写法一
async function func(db){
    let docs = [{},{},{}];
    let promises = docs.map((doc)=>{db.post(doc)})
    let results = await Promise.all(promises)
    console.log(results)
}
//写法二
async function func(db){
    let docs = [{},{},{}];
    let promises = docs.map((doc)=>{db.post(doc)})

    let result = [];
    for(let promise of promises){
        results.push(await promise)
    }
    console.log(results)
}

async函数的实现原理就是Generator函数和自动执行器包装在一个函数里

async function fn(){

}

//等同于;spawn是一个资方执行器
function fn(args){
    return spawn(function* (){
        ...
    })
}

results matching ""

    No results matching ""