ES6 async函数 基本用法详解

简介

async函数也就一种异步解决方案,是在ES2017引入的,为了使得异步更加方便,它可以说是Generator函数的语法糖。
下面有一个例子,分别用asyncGenerator写,大家可以看下区别,

		//generator
        const gen = function* () {
            const result = yield readFile("哈哈", 1000)
            const results = yield readFile("嘻嘻", 500)
            console.log(result)//哈哈
            console.log(results)//嘻嘻
        }
        const readFile = function (data, time) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    ge.next(data)
                }, time)
            })
        }
        const ge = gen();
        ge.next()
		//async
        const gen=async  function(){
            const result=await readFile("哈哈",1000)
            const results=await readFile("嘻嘻",500)
            console.log(result)//哈哈
            console.log(results)//嘻嘻
        }    
        const readFile = function (data, time) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(data)
                }, time)
            })
        }
        gen()

区别:

  • 内置执行器,不需要向Generator函数,需要用next方法执行。
  • 更好的语义,asyncawait比起带星号的函数和yield语义更清楚了。
  • async返回值是 Promise

基本用法

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

    async function set(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve("111")
            })
        })
    }    
    async function fn(){
        var result=await set();
        return result;
    }
    fn().then((data)=>{
        console.log(data)//111
    })

语法

返回Promise对象

这个上面例子已经很清楚了,async函数返回一个Promise对象,当async函数有return语句,那么return的返回值会被then接受到,需要注意的是,需要async函数内部抛出错误,将会被then的第二个参数或者catch捕获到。

    async function fn(){
        throw new Error("出错了")
    }
    fn().then((data)=>{
        console.log(data)
    }).catch((err)=>{
        console.log(err.message)//出错了
    })

另外函数注意的是:
只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

await命令

正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

	async function f() {
	  // 等同于
	  // return 123;
	  return await 123;
	}
	
	f().then(v => console.log(v))
	// 123

需要注意:

  • await后面跟的是thenable对象,那么await会将其等同于Primise对象。
        var obj={
         name:'111',
         then:function(resolve,reject){
             setTimeout(()=>{
                 resolve("hty")
             })
         }
     }
     async function fn(){
         return await obj
     }
     fn().then((data)=>{
         console.log(data)//hty
     })
    
  • 任何一个await语句后面的Promise 对象变为reject状态,那么整个async函数都会中断执行
      async function f() {
       	  await Promise.reject('出错了');
       	  await Promise.resolve('hello world'); // 不会执行
       }
    
    但是有时候,我们希望即使第一个报错,后面也跟着执行,这时候我可以用try..catch包裹或者await后面跟个catch
        async function f() {
             try {
                 await Promise.reject('出错了');
             } catch (e) {
             }
             return await Promise.resolve('hello world');
         }
    
         f().then(v => console.log(v))//hello world
     	
     	//或者
     	async function f1() {
             await Promise.reject('出错了').catch((err) => {
                 console.log(err)
             })
             return await Promise.resolve('hello world');
         }
    
         f1().then(v => console.log(v))
         //出错了
         //hello world
    

使用注意点

  • await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中
  • 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
     // 写法一
     let [foo, bar] = await Promise.all([getFoo(), getBar()]);
     
     // 写法二
     let fooPromise = getFoo();
     let barPromise = getBar();
     let foo = await fooPromise;
     let bar = await barPromise;
    
  • await命令只能用在async函数之中,如果用在普通函数,就会报错
  • async 函数可以保留运行堆栈

async 函数实现原理

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

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}

spawn就是自执行器,结构如下

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

参考文献

阮博士的ES6入门

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值