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