01. Promise作用: 解决回调地狱 1.1 回调地狱: 异步回调 层层嵌套 1.2 js代码分为2种: 同步(默认) 异步 同步: 按照顺序立即执行 异步: 没有顺序 延迟执行 (事件、定时器、ajax) 1.3 层层嵌套: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 let xhr1 = new XMLHttpRequest ()xhr1.open ('get' , 'http://123.57.109.30:3999/api/categoryfirst' ) xhr1.send () xhr1.onload = function ( ) { console .log ('一级' ) console .log (JSON .parse (xhr1.response )) let xhr2 = new XMLHttpRequest ()xhr2.open ('get' , 'http://123.57.109.30:3999/api/categorySecond?firstId=621' ) xhr2.send () xhr2.onload = function ( ) { console .log ('二级' ) console .log (JSON .parse (xhr2.response )) let xhr3 = new XMLHttpRequest ()xhr3.open ('get' , 'http://123.57.109.30:3999/api/categoryThird?secondId=622' ) xhr3.send () xhr3.onload = function ( ) { console .log ('三级' ) console .log (JSON .parse (xhr3.response )) } } } console .log (666 )
02. Promise语法 2.1 调用构造函数 创建Promise实例 1 2 3 4 5 6 7 8 let pro = new Promise ((resolve, reject ) => { setTimeout (function ( ) { reject (2 ) }, 500 ) })
2.2 调用Promise实例对象的then/catch方法 resolve本质就是调用res res是形参 resolve(1)是实参 1 2 3 4 5 6 7 pro.then (res => { console .log (res) }).catch (error => { console .log (error) })
2.3 Promise在创建实例时 里面代码会立即执行 Promise自己是同步的 只有then方法才是异步的 03. Promise工作原理 3.1 Promise是什么? 是ES6新增的构造函数
3.2 Promise作用: 解决回调地狱
3.3 Promise应用场景/原理 Promise对象有三种状态:
pending 进行中(默认状态) 所以一旦创建Promise 里面代码会立即执行 fuifilled 已完成 rejected 已失败 Promise相当于是一个容器 把异步代码放入容器中 状态只能改变一次 不管成功/失败 都会有一个数据结果 4. Promise对象状态只有两种状态: 调用resolve()方法时: 从pending变为fuifilled 调用reject()方法时: 从pending变为rejected 状态只能改变一次 不管成功/失败 都会有一个数据结果 5. Promise状态发生改变后 在任何时候都可以获取结果 Promise实例的then方法获取成功结果 Promise实例的catch方法获取失败结果 6. Promise在创建实例时 里面代码会立即执行 Promise自己是同步的 只有then方法才是异步的 04. Promise使用链式语法解决回调地狱 1. 创建Promise实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let p = new Promise ((resolve, reject ) => { let xhr = new XMLHttpRequest () xhr.open ('get' , 'http://123.57.109.30:3999/api/categoryfirst' ) xhr.send () xhr.onload = function ( ) { console .log ('一级' ) let res = JSON .parse (xhr.response ) resolve (res) } })
2. 取出Promise实例对象结果 1 2 3 p.then (res => { console .log (res) })
3. 取出Promise实例对象的函数结果 1 2 3 4 5 6 7 8 9 p1.then (res => { console .log (res) }) p2.then (res => { console .log (res) }) p3.then (res => { console .log (res) })
4.1 三个实例对象只有url不一样 可封装成函数 帮我们创建Promise实例对象 1 2 3 4 5 6 7 8 9 10 11 12 13 function fn (url ) { return new Promise ((resolve, reject ) => { let xhr = new XMLHttpRequest () xhr.open ('get' , url) xhr.send () xhr.onload = function ( ) { let res = JSON .parse (xhr.response ) resolve (res) } }) }
4.2 调用封装好的Promise实例对象函数 1 2 3 let p1 = fn ('http://123.57.109.30:3999/api/categoryfirst' )let p2 = fn ('http://123.57.109.30:3999/api/categorySecond?firstId=622' )let p3 = fn ('http://123.57.109.30:3999/api/categoryThird?secondId=621' )
4.3 但打印结果还是随机的 因为只要创建代码就会立即执行 p1进行完后 return 返回p2的实例对象 .then可换行 1 2 3 4 5 6 7 8 9 10 11 12 13 p1.then (res => { console .log (res) return p2 }) .then (res => { console .log (res) return p3 }) .then (res => { console .log (res) })
5. Promise是如何解决回调地狱的呢? Promise通过链式调用解决回调地狱 链式调用: 在上一个then里 返回下一个Promise实例 就可以继续后面的then 05. Promise的all/race方法/语法 1. Promise的all方法 Promise.all 把多个Promise实例合并为一个新的Promise 结果为数组 所有Promise要全部成功 才会执行then 只要有一个失败就会执行catch then的结果为数组 finally 不管成功失败都执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function fn (url ) { return new Promise ((resolve, reject ) => { let xhr = new XMLHttpRequest () xhr.open ('get' , url) xhr.send () xhr.onloadend = function ( ) { let res = JSON .parse (xhr.response ) console .log (res) resolve (res) } }) } let p1 = fn ('http://123.57.109.30:3999/api/categoryfirst' )let p2 = fn ('http://123.57.109.30:3999/api/categorySecond?firstId=621' )let p3 = fn ('http://123.57.109.30:3999/api/categoryThird?secondId=622' )
1 2 3 4 5 6 7 8 9 10 11 let p = Promise .all ([p1, p2, p3])p.then (res => { console .log (res) }).catch (error => { console .log (error) }).finally (() => { console .log ('我是finally 我完事了' ) })
2. Promise的race方法 Promise.race 所有Promise谁最先成功 就会执行then 如果有失败就执行catch 这里res不是数组 谁最先成功就是谁 then的结果为最快的那个Promise 1 2 3 4 5 6 let pp = Promise .race ([p1, p2, p3])pp.then (res => { console .log (res, 'race方法' ) }).catch (error => { console .log (error) })
06. async/await异步函数 async异步函数 async/await 主要帮我们执行Promise async作用: 修饰函数 让函数内部使用await await作用: 取代then 并获取then结果 await 只能用于被async修饰的函数 否则报错 加上async变为异步函数 1 2 3 4 5 6 7 8 9 let p = new Promise ((resolve, reject ) => { setTimeout (() => { resolve (1 ) }, 300 ) }) p.then (res => { console .log (res) })
await语法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 async function fn ( ) { let res = await p console .log (res) } fn ()let fn1 = async ( ) => { let res = await p console .log (res) Promise ((res, rej ) => { }).then (res => { }) } fn1 ()
6.1 使用async/await解决回调地狱练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 function fn (url ) { return new Promise ((resolve, reject ) => { let xhr = new XMLHttpRequest () xhr.open ('get' , url) xhr.send () xhr.onloadend = function ( ) { let res = JSON .parse (xhr.response ) resolve (res) } }) } let p1 = fn ('http://123.57.109.30:3999/api/categoryfirst' )let p2 = fn ('http://123.57.109.30:3999/api/categorySecond?firstId=621' )let p3 = fn ('http://123.57.109.30:3999/api/categoryThird?secondId=622' )p1.then (res => { console .log (res) return p2 }).then (res => { console .log (res) return p3 }).then (res => { console .log (res) }) async function fn1 ( ) { let res1 = await p1 console .log ('一级' , res1) let res2 = await p2 console .log ('二级' , res2) let res3 = await p3 console .log ('三级' , res3) } fn1 ()
07. 了解axios底层原理/手写Promise封装xhr 7.1 以前使用的axios 1 2 3 axios.get ('http://123.57.109.30:3999/api/categoryfirst' ).then (res => { console .log (res.data ) })
7.2 axios底层原理 axios其实就是把xhr对象包装在Promise里面 axios方法本质是返回一个Promise对象 Promise内部是原生xhr发送ajax请求 请求成功则用resolve返回给Promise对象 结果给外面的then 1 2 3 4 5 let p = axios.get ('http://123.57.109.30:3999/api/categoryfirst' )console .log (p)p.then (res => { console .log (res.data ) })
7.3 手写Promise源码封装xhr 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 let fn = { get (url ) { return new Promise ((resolve, reject ) => { let xhr = new XMLHttpRequest () xhr.open ('get' , url) xhr.send () xhr.addEventListener ('loadend' , function ( ) { let res = JSON .parse (xhr.response ) resolve (res) }) }) } } let p1 = fn.get ('http://hmajax.itheima.net/api/news' ) console .log (p1)p1.then (res => { console .log (res) }) fn.get ('http://hmajax.itheima.net/api/news' ).then (res => { console .log (res) }) async function fn1 ( ) { let res = await fn.get ('http://hmajax.itheima.net/api/news' ) console .log (res) } fn1 ()
7.4 使用axios异步函数依次加载-async/await 使用async/await 依次加载一 二 三级的列表 1 2 3 4 5 6 7 8 9 10 11 12 async function fn ( ) { let res1 = await axios.get ('http://123.57.109.30:3999/api/categoryfirst' ) console .log (res1.data ) let res2 = await axios.get ('http://123.57.109.30:3999/api/categorySecond?firstId=621' ) console .log (res2.data ) let res3 = await axios.get ('http://123.57.109.30:3999/api/categoryThird?secondId=622' ) console .log (res3.data ) } fn ()
08. try-catch捕获异常 Error对象: 内置对象 提示错误代码信息 throw错误信息: 抛出异常 让控制台变红 try-catch语法: 捕捉错误代码 8.1 try-throw语法 1 2 3 4 5 6 7 8 9 10 try { // 这里代码如果遇到错误 就会执行catch console.log(1) // 在try里写throw就会执行catch throw '错误信息' } catch (error) { console.log(error) } finally { console.log(666) }
8.2 应用场景 8.3 用于结束forEach(面试题) throw主动抛出错误 就会结束try代码 然后立即执行catch 1 2 3 4 5 6 7 8 9 10 11 12 try { let arr = [10 ,20 ,30 ,40 ,50 ] arr.forEach (i => { if (i == 30 ) { throw 2 } console .log (i) }) } catch (error) { console .log (error) }
8.4 捕捉await的错误信息 错误的Promise走catch 但await走不了catch 只能then 所以使用try-catch方法 配合捕捉await错误 1 2 3 4 5 6 7 8 9 10 11 async function fn ( ) { try { let res = await axios.get ('http://1hmajax.itheima.net/api/news' ) console .log (res.data ) } catch (error) { console .log (error) } } fn ()