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" 的值了。