javascript ES6 新特性之 Promise,ES7 async / await

es6 一經推出,Promise 就一直被你們所關注。那麼,爲何 Promise 會被你們這樣關注呢?答案很簡單,Promise 優化了回調函數的用法,讓本來須要縱向一層一層嵌套的回調函數實現了橫向的調用,也就是鏈式調用。es6

咱們先來看下面的代碼:dom

1 function getData(){ 2     setTimeout(()=>{ 3         var name = "zhangsan"; 4     }, 1000) 5 } 6 
7 getData();

 

在上面的代碼中,咱們模擬了一個異步時間,一秒後輸出 name = "zhangsan"; 那如何當咱們調用 getData() 方法的時候拿到這個 name 值呢,這時可能會有人說 return 出來就能夠了,以下:異步

1 function getData(){ 2     setTimeout(()=>{ 3         var name = "zhangsan"; 4     }, 1000); 5     return name 6 } 7 
8 console.log(getData()); // ReferenceError: name is not defined

 

結果卻報錯,這時因爲當咱們執行 getData() 函數的時候,因爲 setTimeout 異步執行,因此先執行第五行的 return name;一秒以後才聲明 name = "zhangsan"; 因此會 name is not defined 的錯。async

那有人可能就會說把 return 放到 setTimeout 裏面執行,以下:函數

1 function getData(){ 2     setTimeout(()=>{ 3         var name = "zhangsan"; 4         return name 5     }, 1000); 6 } 7 
8 console.log(getData()); // undefined

仍然拿不到 name 值,報 undefined 的錯,這個緣由就很簡單了,由於執行 getData() 的時候,方法沒有返回值,因此報 undefined,一秒以後再執行 setTimeout。優化

 

經過以上報錯咱們能夠知道,setTimeout 執行完成後才能拿到 name 的值,因此咱們就須要在執行結束後再經過回調的方式拿到 name 的值,以下:spa

 1 function getData(callback){  2     setTimeout(()=>{  3         var name = "zhangsan";  4  callback(name)  5     }, 1000)  6 }  7 
 8 getData((data)=>{  9     console.log(data) // zhangsan
10 });

 

咱們在 getData() 方法內出入一個回調函數,當 setTimeout 執行結束後調用此方法並將 name 值傳入,這樣咱們就能拿到 name 值了。這裏咱們用到了 ES6 的另外一個特性 箭頭函數,咱們姑且先將它 ( ) => { } 和 function( ){ } 看作是等價的。code

 

上述方法能夠解決咱們的問題,可是在代碼上咱們就須要再多些一個回調函數,這樣看起來很不友好,因此 ES6 爲咱們提供了 Promise 這個特性。blog

1 var p = new Promise((resolve, reject) => { 2     setTimeout(() => { 3         var name = "zhangsan"; 4  resolve(name) 5     }, 1000) 6 }); 7 p.then((data) => { 8  console.log(data); 9 });  // zhangsan

 

上面的代碼等同於下面的:get

 1 function getData(resolve, reject) {  2     setTimeout(() => {  3         var name = "zhangsan";  4  resolve(name)  5     }, 1000)  6 }  7 
 8 var p = new Promise(getData);  9 
10 p.then((data)=> { 11  console.log(data); 12 });  // zhangsan

咱們能夠看出,Promise 構造函數接受一個函數做爲參數,函數裏面有兩個參數 resolve 和 reject ,其中 resolve 做爲執行成功的函數, reject 做爲執行失敗的函數。以下:

 1 function getData(resolve, reject) {  2     setTimeout(() => {  3         var name = "zhangsan";  4         if(Math.random() < .5){  5  resolve(name)  6         } else{  7             reject("獲取 name 失敗")  8  }  9     }, 1000) 10 } 11 
12 var p = new Promise(getData); 13 
14 p.then((data)=> { 15     console.log(data);   // zhangsan
16 },(data)=>{ 17     console.log(data);   // 獲取 name 失敗
18 }) ;

咱們定義一個隨機數,當隨機數小於 0.5 時會走 p.then() 的第一個函數,也就是正確的 resolve,當隨機數大於 0.5 時,會走第二個函數,也就是錯誤的 reject。

Promise 除了 then 以外還提供了一個一個 catch 的方法,以下:

 1 function getData(resolve, reject) {  2     setTimeout(() => {  3         var name = "zhangsan";  4  resolve(name)  5     }, 1000)  6 }  7 
 8 var p = new Promise(getData);  9 
10 p.then((name)=> { 11     console.log(name);   // zhangsan
12  console.log(age) 13 }).catch((reason)=>{ 14     console.log(reason)  // ReferenceError: age is not defined
15 }) ;

在上面的代碼中咱們在 p.then() 的方法內輸出了一個 age ,可是這個 age 咱們既沒有在全局定義,也沒有經過傳值的方式傳過來,若是咱們不寫底下的 catch() 方法的話會報 ReferenceError: age is not defined,同時程序會崩掉,加上 .chath 方法後 ReferenceError: age is not defined 會在此方法內輸出,程序並不會崩掉,這個就相似於咱們經常使用的 try / catch 方法。

 

在 ES7 中,還給咱們提供了更爲方便的異步操做方法 async / await ;以下:

 1 async function getData() {  2     return new Promise((resolve, reject) => {  3         setTimeout(() => {  4             var name = "zhangsan";  5  resolve(name)  6         }, 1000)  7  })  8 }  9 
10 async function test() { 11     var data = await getData(); 12  console.log(data); 13 } 14 
15 test();  // zhangsan

咱們將以前的代碼改成上面這樣,輸出結果依然是 zhangsan,這裏使用了 async / await 的組合,咱們將上面的代碼簡化一下:

 1 async function getData() {  2     var name = "zhangsan";  3     return name;  4 }  5 
 6 console.log(getData());  // Promise { 'zhangsan' }
 7 
 8 async function test(){  9     var data = await getData(); 10  console.log(data); 11 } 12 
13 test();  // zhangsan

 

咱們在 function getData( ){ } 前面加了一個 async 的字段,該函數就被認定爲一個異步函數,而後在調用 getData( ) 的方法前面加一個 await 的字段,這就是一個異步操做,意思就是等 getData( ){ } 異步函數執行完之後再調用此方法,這樣咱們在 getData() 的函數內加一個 setTimeout 的異步方法後,也是等異步方法執行完之後在調用,這樣就能拿到 name = "zhangsan" 的值了。

相關文章
相關標籤/搜索