koa2第一天 async詳解


一、什么是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關鍵字
    在Generator章節中我們熟悉了yield關鍵字,yield關鍵字只能使用在Generator函數中,同樣,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不斷發展的魅力所在。


---------------------
作者:恰恰虎
來源:CSDN
原文:https://blog.csdn.net/tcy83/article/details/80544048
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM