Promise 是 ES6 的新特性,提供了對 js 異步編程控制的新的解決方案,在過去書寫異步代碼時要靠回調函數,當異步操做依賴於其餘異步操做的返回值時,會出現一種現象,被程序員們稱爲 「回調地獄」,即多層回調函數嵌套,這種代碼的可讀性、維護性都不好,所以誕生了 Promise,固然 Promise 並非徹底擺脫回調,而只是改變了傳遞迴調的位置,大大減小了回調函數嵌套。程序員
<br/>編程
Promise 中的代碼默認是同步執行的,then
方法中的回調在微任務隊列中執行,在 Promise 的 then
方法中支持傳入兩個參數,一個是成功的回調,一個是失敗的回調,在 Promise 中調用了 resolve
方法,就會在 then
中執行成功的回調,調用了 reject
方法,就會在 then
中執行失敗的回調,成功的回調和失敗的回調只能執行一個,resolve
和 reject
方法調用時傳入的參數會傳遞給 then
方法中對應的回調函數。數組
// 執行 resolve let p = new Promise((resolve, reject) => { console.log(1); resovle(3); }); console.log(2); p.then(data => { console.log(data); }, err => { console.log(err); }); // 1 // 2 // 3
// 執行 reject let p = new Promise((resolve, reject) => { reject(); }); p.then(() => { console.log(1); }, () => { console.log(2); }); // 2
若是 Promise 中發生錯誤,就會在 then
中執行失敗的回調。異步
// 失敗的回調 let p = new Primise((resolve, reject) => { throw new Error(); }); p.then(() => { console.log(1); }, () => { console.log("報錯啦"); }); // 報錯啦
當同一個 Promise 實例的 then
方法屢次調用時,就會屢次執行。異步編程
// 屢次調用 then let p = new Promise((resolve, reject) => { resolve("成功"); }); p.then(data => { console.log(data); }); p.then(data => { console.log(data); }); // 成功 // 成功
Promise 支持鏈式調用,每次調用一次 then
方法都會返回一個新的 Promise實例,若是該 then 方法中執行的回調函數有返回值,而且這個返回值會做爲返回的下一個 Promise 實例的 then
方法回調的參數,若是 then
方法的返回值是一個 Promise 實例,那就返回一個新的 Promise 實例,將 then
返回的 Promise 實例執行後的結果做爲返回 Promise 實例回調的參數。函數
// 鏈式調用 then function read(url) { return new Promise((resolve, reject) => { fs.readFile(url, "utf8", (err, data) => { if (err) reject(err); resolve(data); }) }); } read("1.txt").then(data => { // 假設此時讀到的內容爲 Hello world return data; }, err => { console.log(err); }).then(data => { console.log(data); // Hello world }, err => { console.log(err); }); read("1.txt").then(data => { // 假如此時讀到的 1.txt 的內容爲 2.txt 的字符串,2.txt 的內容爲 Hello world return read(data); }, err => { console.log(err); }).then(data => { console.log(data); // Hello world }, err => { console.log(err); });
在 Promise 實例的 then
中若是有錯誤產生,在返回的新的 Promise 實例中的 then
方法中會執行錯誤的回調。this
// 鏈式調用 then 出錯 let p = new Promise((resolve, reject) => { resolve(); }); p.then(() => { console.log("success", 1); throw new Error(); }, () => { console.log("error", 1); }).then(() => { console.log("success", 2); }, () => { console.log("error", 2) }) // success 1 // error 2
在 Promise 中有三個狀態:url
Promise 實例的狀態只能從 pending
到 fulfilled
或從 pending
到 rejected
,狀態一旦發生變化就不可逆,因此 Promise 實現鏈式調用與 jQuery 不一樣,返回的不是 this
,只能是一個新的 Promise。spa
在 Promise 中實例的 catch
方法能夠捕獲鏈式調用中的異常,不須要每次調用 then
方法中都傳入錯誤的回調,在鏈式調用的過程當中只要有任何一個 then
中出現錯誤,都會被 catch
方法捕獲到。code
// catch 方法 let p = new Promise((resolve, reject) => { resolve(); }); p.then(() => { throw new Error(); console.log("success", 1); }).then(() => { console.log("success", 2); }).catch(() => { console.log('出錯了'); }); // 出錯了 p.then(() => { console.log("success", 1); }).then(() => { throw new Error(); console.log("success", 2); }).catch(() => { console.log('出錯了'); }); // success 1 // 出錯了
Promise 中的靜態方法 all
能夠實現多個 Promise 實例的並行,當全部結果都爲成功時,返回一個數組,該數組存儲的爲每個 Promise 實例的返回結果,每個 Promise 實例的返回順序前後不固定,可是返回值的數組內存儲每個 Promise 的返回值的結果按照最初傳入的順序排列,all
方法的返回值爲一個新的 Promise 實例,返回的數組做爲返回新 Promise 的 then
方法成功回調的參數。
當 all
傳入的參數數組中的 Promise 實例執行時,只要有一個失敗,則直接返回該 Promise 實例失敗的結果或錯誤信息。
// Promise.all 方法 let p1 = new Promise((resolve, reject) => { resolve(1); }); let p2 = new Promise((resolve, reject) => { resolve(2); }); Promise.all([p1, p2]).then(data => { console.log(data); }); // [1, 2]
// Promise.all 錯誤捕獲 let p1 = new Promise((resolve, reject) => { resolve(1); }); let p2 = new Promise((resolve, reject) => { reject(2); }); Promise.all([p1, p2]).then(data => { console.log(data); }).catch(err => { console.log(err); }); // 2
Promise 的靜態方法 race
的用法和 all
相似,參數同爲一個存儲 Promise 實例的數組,返回值一樣是一個新的 Promise 的實例,不一樣的是,數組中的 Promise 實例只有一個結果爲成功,那就直接返回這個結果(只取出最快返回的結果),在沒有成功的結果以前有一個出錯,就直接返回這個錯誤。
// Promise.race 方法 let p1 = new Promise((resolve, reject) => { setTimeout(() => resolve(1), 2000); }); let p2 = new Promise((resolve, reject) => { setTimeout(() => resolve(2), 1000); }); Promise.race([p1, p2]).then(data => { console.log(data); }).catch(err => { console.log(err); }); // 2
// Promise.race 錯誤捕獲 let p1 = new Promise((resolve, reject) => { setTimeout(() => reject(1), 1000); }); let p2 = new Promise((resolve, reject) => { setTimeout(() => resolve(2), 2000); }); Promise.race([p1, p2]).then(data => { console.log(data); }).catch(err => { console.log(err); }); // 1
Promise 的靜態方法 resolve
能夠直接將 Promise 的狀態變爲成功並返回一個新的 Promise 實例,resolve
的參數會傳遞給返回的新 Promise 實例 then
中成功回調。
// Promise.resolve 方法 Promise.resolve('hello').then(data => { console.log(data); }); // hello
Promise 的靜態方法 reject
與 resolve
使用徹底相同,都返回一個新的 Promise 實例,不一樣的是 reject
的參數會傳遞給新 Promise 實例的 then
方法失敗回調。
// Promise.reject 方法 Promise.reject('出錯了').then(null, err => { console.log(err); }); // 出錯了
當成功的回調不傳遞時,可使用 null
代替,由於 null
做爲參數會被忽略掉,將參數穿透到下一個 then
的回調中。