async函数

什么是async函数?

Generator的语法糖,让异步操作变得更加方便

const asyncFunc = async funtion(){
  const f1 = await readFile('./a.txt')
  const f2 = await readFile('./b.txt')
  console.log(f1.toString())  
  console.log(f2.toString())    
}

相比于Generator的改进

  1. Generator的执行必须依靠执行器,这也就造成了co模块的出现。而async函数中自带执行器,调用时只需要一行--asyncFunc()。而Generator需要首先获得遍历器,再执行next()或者使用co模块,才能真正调用
  2. Generator的yield后只能跟Promise对象或Thunk函数,而async函数的await后可以跟Promise对象和原始类型的数据(会自动转成立即执行resolved的Promise)
  3. 返回值是Promise对象,可以直接对其进行.then调用。而Generator返回iterator接口,很麻烦。

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.getAvatar('jack').then();

        // 箭头函数
        const foo = async () => {};

返回Promise对象

async funtion foo(){
  return 'hello'  
}
foo().then(resolved => console.log(resolved))
// hello

当抛出异常时,导致返回的Promise对象状态变为rejected,错误对象会被rejected处理函数捕获

async function foo() {
            throw new Error('出错了')
        }
        foo().then(
            v => console.log(v),
            e => {console.log(e)}
            )

Promise对象的状态变化

当async函数中存在多个await语句时,会等到所有await一个个执行完,才会改变状态,执行.then(除非遇到错误异常或return语句)

async function foo(url) {
            let response = await fetch(url);
            let html = await response.text();
            return html.match(/<title>([\s\S]+)<\/title>/i)[1];
        }
        foo('').then(console.log)

以上代码中,只有等到fetch请求结束、获取响应文本结束、匹配结束,才会改变promise状态,执行.then

await命令

通常情况下,await命令后跟一个promise对象,返回该对象的结果。如果不是,就返回对应的值

还有一种情况,await后是一个定义then的方法,也会被当做是promise对象处理

当await后面的promise状态变为rejected时,就会被catch捕捉。只要某个await后的promise状态变为rejected,后面的await不会继续执行

async function foo() {
                await Promise.reject('出错了') // ‘出错了’
                await Promise.resolve('hello world') // 不会执行
        }

        foo()
        .then(v=>{
            console.log(v)
        })
        .catch(e=>{
            console.log(e)
        })

如果想要前一个异步操作失败不影响后面异步操作的执行,可以通过以下两种方式

async function foo() {
            try{
                await Promise.reject('出错了')
            }catch(e){

            }
            return await Promise.resolve('hello world')
        }

        foo()
        .then(v=>{
            console.log(v)
        })

        async function foo() {
            await Promise.reject('出错了').catch(e => console.log(e))
            return await Promise.resolve('hello world')
        }
        foo()
        .then(v=>{
            console.log(v)
        })

顶层await

通常情况下await命令只能在async函数中使用,而为了达到模块异步加载问题,目前有一个语法提案,允许在async函数外部写await。

当加载某个模块时,如果其中包含异步操作,加载方无法确定被加载模块是否执行结束。因此在导出对象时添加await,直到异步操作完成才能被其他模块导入。

const dynamic = import(someMission);
const data = fetch(url);
export const output = someProcess((await dynamic).default, await data);

 

使用注意

  1. 因为await后面跟着的promise对象,只要reject就会执行catch代码,中止继续执行。因此最好将所有await放在try..catch...代码块中
  2. await只能在async函数中使用,否则报错
  3. 如果有多个await,且后面的异步操作不存在继发关系,最好同时触发
    1.   
      async function foo(){
        await Promise.all([getfoo(), getimg()])  
      }
posted @ 2020-04-17 14:35  ashen1999  阅读(167)  评论(0编辑  收藏  举报