• Home
  • About
    • 谢朝森的个人博客 photo

      谢朝森的个人博客

      该博客主要用来记录个人学习,生活。帮助个人成长以及分享知识的一隅之地。

    • Learn More
    • Twitter
    • Facebook
    • Instagram
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

async

async函数

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

以下是使用Generator函数和async函数来读取文件的方式

    const fs = require('fs');
    const readFile = function(filename){
        return new Promise(function(resolve,reject){
            fs.readFile(filename,function(err,data){
                if (err) return reject(err);
                resolve(data);
            })
        })
    }
    const gen = function* (){
        let x = yield readFile('Afile');
        let y = yield readFile('Bfile');
        console.log(x.toString());
        console.log(y.toString());
    }
    const g = gen();
    g.next();
    // 使用async函数的写法
    const asyncReadFile = async function(){
        let x = await readFile('Afile');
        let y = await readFile('Bfile');
        console.log(x.toString());
        console.log(y.toString());
    }
    asyncReadFile();

async函数的优化体现在以下方面

  • 内置执行器

    async函数内部自带执行器,不需要再编写函数执行器,而Generator函数自动执行需要执行器或者是co模块. 因此,调用async函数只需要在函数名后面加上()即可。

  • 语义化更加的清晰

    await和async比*和yield语义更加的清晰。

  • 使用更加灵活

    co模块规定,yield后面的表达式必须是Thunk函数或者是Promise对象。而async函数的await后面表达式不限定类型, 可以是Thunk函数,Promise对象,也可以是基本数据类型。

  • 返回值是Promise对象

    async函数的返回值是Promise对象,可以直接使用then方法进行操作,而Generator函数执行的返回值是Iterator对象, 需要使用next()方法进行操作。

async语法

  • async函数返回的是Promise对象
  • async内部的return语句返回的值,会成为then方法回调函数的参数。
    async function f(){
        return 'async';
    }
    f().then(v=>{console.log(v)}); // async
  • async函数内部抛出的错误,会造成返回的Promise状态变成reject;抛出的错误也会被catch方法所捕获。
    async function fn(){
        return new Error('出错了');
    }
    fn().then(()=>{console.log(1)}).catch(e=>{console.log(e)}); // 出错了
  • Promise对象的状态变化 async函数返回的Promise对象的状态,必须要等到该函数内部所有的await命令后面的Promise对象执行完,才会发生状态的改变, 除非是遇到错误或者是return语句,否则当await后面的Promise对象没有执行完成之前,async内部的所有的Promise的状态就都是pending状态。
  • await命令 一般情况,await命令后面是一个Promise对象,如果不是的话,就会被立即转成一个resolve状态的Promise状态。
    async function fn(){
        return await 123;
    }
    fn().then(v=>{console.log(v)})  // 123

await后面的Promise转台如果变成reject的话,那么会被catch的回调方法所捕获到。

    async function fn(){
        return new Error('报错了');
    }
    fn().then(v=>{console.log(v)}).catch(e=>{console.log(e)}); // 报错了
  • 只要一个await语句后面的Promise变成reject,那么整个async就都会被中断。整个async函数返回的Promise状态就变成了reject。
  • 处理某个await后面的Promise出错的方法 如果不确定某个await后面的Promise是否会出错的话,将其放入到try…catch中。

使用注意点⚠️

  • 尽可能的将可能会出错的await后面的Promise写在try…catch语句中
  • 如果多个await之间不存在相互的依赖关系,那么可以让他们同时触发调用
    let foo = await getFoo();
    let bar = await getBar();
    // 以上两个await后面的Promise没有关联,可以采用如下的方式,将其同时调用
    let [foo,bar] = await Promise.all([getFoo(),getBar()]);
  • await只能用在async函数中,如果用于普通的函数的话,就会报错。

异步Generator函数

异步Generator函数就是async函数和Generator函数的结合。

    async function* fn(){
        yield 'hello world';
    }
    const genObj = fn();
    fn.next().value.then(v=>console.log(v));

yield* 语句

yield* 也可以跟上一个异步遍历器

    async function* gen1(){
        yield 'a';
        yield 'b';
        return 2;
    }
    async function* gen2(){
       const results = yield* gen1()  // results:2
    }