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