zoukankan      html  css  js  c++  java
  • 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不断发展的魅力所在。

  • 相关阅读:
    Sum Root to Leaf Numbers 解答
    459. Repeated Substring Pattern
    71. Simplify Path
    89. Gray Code
    73. Set Matrix Zeroes
    297. Serialize and Deserialize Binary Tree
    449. Serialize and Deserialize BST
    451. Sort Characters By Frequency
    165. Compare Version Numbers
    447. Number of Boomerangs
  • 原文地址:https://www.cnblogs.com/deng-jie/p/12703209.html
Copyright © 2011-2022 走看看