• async详解


    转载:https://zhuanlan.zhihu.com/p/49742331

    一、什么是async

    async其实是ES7的才有的关键字,放在这里说,其实是和我们前面所说的Promise,Generator有很大关联的。async的意思是"异步",顾名思义是有关异步操作有关的关键字。下面我们就来构造一个async方法。

    async function helloAsync(){
        return "helloAsync";
      }
      console.log(helloAsync())//Promise {<resolved>: "helloAsync"}
    

      

    申明async方法比较简单,只需要在普通的函数前加上"async"关键字即可。我们执行下这个函数,发现并没有返回字符串"helloAsync",而是通过Promise.resolved()将字符串封装成了一个Promise对象返回。

    既然是返回的Promise对象,我们就是用then方法来处理。

    async function helloAsync(){
       	return "helloAsync";
       }
      helloAsync().then(v=>{
         console.log(v);//"helloAsync"
      })

    到这,道友们可能纳闷了,就是封装一个Promise的对象返回,这有个毛用啊。别急,await关键字闪亮登场。

     

    二、await关键字

    await关键字也不能单独使用,是需要使用在async方法中。 await字面意思是"等待",那它是在等什么呢?它是在等待后面表达式的执行结果。

    function testAwait(){
       return new Promise((resolve) => {
              setTimeout(function(){
              	console.log("testAwait");
              	resolve();
              }, 1000);
           });
      	}
      async function helloAsync(){
      	await testAwait();
      	console.log("helloAsync");
      }
      helloAsync();

    我们来分析下这段代码

    1、testAwait()方法中new一个Promise对象返回,promise对象中用setTimeout模拟一个异步过程,即1s后打印"testAwait"。

    2、helloAsync()方法中,await testAwait(),表示将阻塞这里,等待testAwait这个异步方法执行并返回结果后,才继续下面的代码。

    执行下,1s后打印了下面的日志。

    到此,道友们是不是理解了await的作用,就是阻塞主函数的执行,直到后面的Promise函数返回结果。

    聪明的道友可能要问,await后面只能 是Promise对象么?答案是否定的,可以是字符串,布尔值,数值以及普通函数。

    function testAwait(){
      	setTimeout(function(){
              	console.log("testAwait");
              }, 1000);
      	}
      async function helloAsync(){
      	await testAwait();
      	console.log("helloAsync");
      }
      helloAsync();

    执行结果:

    方法没有报错,说明await后面是支持非Promise函数的,但是执行的结果是不一样的,所以await针对所跟的表达式不同,有两种处理方式:

    1、对于Promise对象,await会阻塞主函数的执行,等待 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果,然后继续执行主函数接下来的代码。

    2、对于非Promise对象,await等待函数或者直接量的返回,而不是等待其执行结果。

    我们知道Promise对象有两种状态,除了resolved,还有rejected,我们来看下如果promise对象变为rejected,会如何处理。

    function testAwait(){
      	return Promise.reject("error");
     }
      async function helloAsync(){
      	await testAwait();
      	console.log("helloAsync");//没有打印
      }
      helloAsync().then(v=>{
          console.log(v);
      }).catch(e=>{
         console.log(e);//"error"
      });

    从执行结果看,返回reject状态被外层的catch捕获到,然后终止了后面的执行。

    但是在有些情况下,出错后是希望继续执行,而不是中断。对于这种情况可以采用tcy...catch在函数内部捕获异常。

    function testAwait(){
      		return Promise.reject("error");
      	}
      async function helloAsync(){
      	try{
           await testAwait();
      	}catch(e){
      		console.log("this error:"+e)//this error:error
      	} 	
      	console.log("helloAsync");//helloAsync
      }
      helloAsync().then(v=>{
      }).catch(e=>{
         console.log(e);//没有打印
      });
    

      

    异常被try...catch捕获后,继续执行下面的代码,没有导致中断。

    三、应用场景

    上面说到,await可以阻塞主函数,直到后面的Promise对象执行完成。这个特性就能很轻松的解决按顺序控制异步操作,即我们前一章节讲的异步流程的问题。

    道友们还记得在Generator章节的肚包鸡的制作过程的实例,我们用async/await来重写这个例子,并比较下两者实现的区别。

    //准备
       function prepare(){
       	   return new Promise((resolve) => {
               setTimeout(function(){
                 console.log("prepare chicken");
                 resolve();
             },500)
           });  
       }
     
       //炒鸡
       function fired(){
            return new Promise((resolve) => {
               setTimeout(function(){
                 console.log("fired chicken");
                 resolve();
             },500)
           }); 
       }
       //炖鸡
       function stewed(){
            return new Promise((resolve) => {
               setTimeout(function(){
                 console.log("stewed chicken");
                 resolve();
             },500)
           }); 
       }
       //上料
       function sdd(){
            return new Promise((resolve) => {
               setTimeout(function(){
                 console.log("sdd chicken");
                 resolve();
             },500)
           }); 
       }
       //上菜
       function serve(){
            return new Promise((resolve) => {
               setTimeout(function(){
                 console.log("serve chicken");
                 resolve();
             },500)
           });
       }
       async function task(){
       	console.log("start task");
      	await prepare();
      	await fired();
      	await stewed();
      	await sdd();
      	await serve();
      	console.log("end task");
      }
      task();
    

      

    这段代码看上去神清气爽,我们来分析下代码:

    1、首先每个制作异步过程封装成Promise对象。

    2、利用await阻塞原理,实现每个制作的顺序执行。

    相比较Generator实现,无需run流程函数,完美的实现了异步流程。

    四、总结

    从Promise到Generator,再到async,对于异步编程的解决方案越来越完美,这就是ES6不断发展的魅力所在。

  • 相关阅读:
    SASS常用方法
    Vue 全局过滤和局部过滤
    Java进阶知识点8:高可扩展架构的利器
    InnoDB MVCC RR隔离级别下的数据可见性总结
    记一次诡异的网络故障排除
    数据库的读锁和写锁在业务上的应用场景总结
    Gradle配置IDEA正常识别JPA Metamodel Generator动态生成的代码
    程序员容易读错的单词
    Java进阶知识点7:不要只会写synchronized
    Java进阶知识点6:并发容器背后的设计理念
  • 原文地址:https://www.cnblogs.com/deng-jie/p/12703209.html
Copyright © 2020-2023  润新知