[TOC] #### 1. 回調地獄 --- 回調地獄: 在回調函數中嵌套回調函數 因為 ajax 請求是異步的,所以想要使用上一次請求的結果作為請求參數,所以必須在上一次請求的回調函數中執行下次請求,這種寫法非常繁瑣,我們親切的把它稱之為 `回調地獄` ES6 原生提供了 Promise 對象,Promise 解決了回調地獄的問題 回調地獄代碼示例: ```javascript // 第一次請求 $.ajax({ url: './login.json', success(res) { // 使用第一次請求的結果發送第二次請求 $.ajax({ url: './user.json', data: { id: res.id }, success(res) { // 使用第二次請求的結果發送第三次請求 $.ajax({ url: './getUserList.json', data: { where: res.userinfo.name }, success(res) { console.log('res', res) } }) } }) } }) ``` #### 2. Promise 的使用 --- Promise 是一個構造函數,接受一個函數作為參數,通過 new 關鍵字實例化 ```javascript new Promise((resolve, reject) => { }); ``` 查看 Promise 實例的屬性 ```javascript const promise = new Promise((resolve, reject) => { }); console.dir(promise); ``` 得出 Promise 實例有兩個屬性: state(狀態),result(結果) ![](https://img.itqaq.com/art/content/00bb197cbff649bcdc1cfc68b74b9382.png) #### 3. Promise 的狀態 --- Promise 實例的三種狀態 ``` pending (準備,待解決,進行中) fulfilled(已完成,成功) rejected (已拒絕,失敗) ``` **Promise 狀態的改變:** 通過調用 resolve(),reject() 改變當前 promise 對象的狀態,promise 對象的狀態改變是一次性的。 ```javascript const promise = new Promise((resolve, reject) => { // 使當前 promise 對象狀態改為 fulfilled // resolve() // 使當前 promise 對象狀態改為 rejected // reject() }); ``` #### 4. Promise 的結果 --- Promise 實例的另外一個屬性 result 的值就是調用 resolve() 或 reject() 的參數 ```javascript const promise = new Promise((resolve, reject) => { resolve({ name: 'liang' }) }); console.dir(promise); const promise2 = new Promise((resolve, reject) => { reject({ name: 'wang' }) }); console.dir(promise2); ``` ![](https://img.itqaq.com/art/content/f60a84024ef85ab2ef14f4d2d30d58ed.png) #### 5. Promise 的 then 方法 --- then 方法是第一個參數在 promise 狀態是 fulfilled 執行,第二個參數在 promise 狀態是 rejected 執行 then 方法的返回值是一個 promise 對象 ```javascript const p = new Promise((resolve, reject) => { reject({ name: 'liang' }) }); p.then(res => { // 當 promise 狀態是 fulfilled 執行 console.log('成功時調用', res) }, reason => { // 當 promise 狀態是 rejected 執行 console.log('失敗時調用', reason) }); ``` 在 then 方法中使用 return 可以將 then 方法返回的 promise 實例改為 fulfilled 狀態 在 then 方法中,如果代碼出錯(錯誤異常),會將返回的 promise 實例狀態改為 rejected ```javascript // 如果 promise 的狀態不改變 then 方法無法執行 const p = new Promise((resolve, reject) => { resolve() }); const t = p.then(res => { console.log('成功時調用', res) // 在 then 方法中使用 return 可以將 then 方法返回的 promise 實例狀態改為 fulfilled // return 123 // 如果這里的代碼出錯 會將 t 實例的狀態改為 rejected console.log(a); }, reason => { console.log('失敗時調用', reason) }); t.then(res => { // res 123 console.log('t 成功', res) }, reason => { console.log('t 失敗', reason) }) ``` #### 6. Promise 的 catch 方法 --- **catch 方法參數中的函數執行時機 ?** 1\. 當 promise 實例狀態改為 rejected 時 2\. promise 構造函數的參數方法體中有錯誤發生(其實也是狀態變為 rejected ) ```javascript const p = new Promise((resolve, reject) => { // 下面兩種錯誤都會觸發 catch 方法 // reject('有錯誤') // throw new Error('出錯了') }); p.catch(res => { console.log('res', res) }) ``` catch 方法 和 then 方法的第二個參數都能捕捉到 promise 實例狀態改為 rejected 時的情況,那么平時推薦怎么用 ?下面是 Promise 最常見的寫法,推薦這么使用 ```javascript const p = new Promise((resolve, reject) => { resolve() // reject() }); p.then(res => { console.log('res', res) }).catch(reason => { console.log('reason', reason) }) ``` #### 7. 回調地獄的解決方案 --- 回調地獄寫法 ![](https://img.itqaq.com/art/content/7f4803d23eab0fe3d6c7fb243c46f915.png) 第一次改造: 使用 Promise ![](https://img.itqaq.com/art/content/026e20da54c5e020fcda29e0c8aee4c6.png) 第二次改造: 封裝函數 ![](https://img.itqaq.com/art/content/1595674f4423c8695318bd752cab0de3.png) 第三次改造: 終極解決方案(使用 async + await) ![](https://img.itqaq.com/art/content/acbac63776f495512c7a8b8dd5eb26a1.png)