取代then函数, 来提取Promise的值
Promise链式调用
// 目标: 使用Promise的链式调用解决问题 // 前提: axios函数在原地返回的就是一个Promise对象 let pname = '' axios.get('http://ajax-api.itheima.net/api/province').then(res => { // 2. 获取某个省, 对应的城市列表 pname = res.data.data[5]; return axios.get(`http://ajax-api.itheima.net/api/city?pname=${pname}`) }).then(res => { // 3. 获取某个市, 对应的地区列表 let cname = res.data.data[0] return axios.get(`http://ajax-api.itheima.net/api/area?pname=${pname}&cname=${cname}`) }).then(res => { console.log(res); })
async await语法
async function 函数名() { const result = await Promise对象 // 拿到Promise对象内成功的结果继续向下执行 }
示例
// 目标: 掌握下async和await语法 // 目的: 用await取代then函数, 来提取成功的值在原地 let p = new Promise((resolve, reject) => { setTimeout(() => { resolve('成功的值') }, 2000) }) // 普通函数: async+await async function fn() { const result = await p console.log(result) } fn() // 箭头函数: async+await const myFn = async () => { const result = await p console.log(result) } myFn()
注意事项
-
await 必须用在async修饰的函数内
-
async修饰后, 此函数为异步函数
-
await之后一般跟promise
-
await不能捕获失败结果, 需要使用try+catch关键字捕获
-
/* try和catch语法 try { // 这里放可能在执行中报错的代码 // 如果报错会终止代码继续执行, 直接跳转进catch里执行 } catch (err) { // err接收try大括号内报错抛出的异常代码 } */ let p = new Promise((resolve, reject) => { setTimeout(() => { // resolve(1) reject(new Error('失败')) }, 2000) }) async function myFn() { try { const res = await p console.log(res); } catch (err) { console.error(err) } } myFn()
使用async await优化回调地狱
// 目标: 使用Promise的链式调用解决问题 // 前提: axios函数在原地返回的就是一个Promise对象 async function f() { const provinces = await axios.get('http://ajax-api.itheima.net/api/province') const pname = provinces.data.data[5] const citys = await axios.get(`http://ajax-api.itheima.net/api/city?pname=${pname}`) const cname = citys.data.data[0] const areas = await axios.get(`http://ajax-api.itheima.net/api/area?pname=${pname}&cname=${cname}`) return areas } f()
EventLoop事件循环
JavaScript 是一门单线程执行的脚本语言。也就是说,同一时间只能做一件事情。
javaScript要运行在宿主环境中(浏览器,nodejs)下。浏览器内部有执行js代码的引擎(V8引擎)
排队是任务是以事件及其回调的方式存在的。
当事件(用户的点击,图片的成功加载)发生时,将其回调添加到任务队列;主线程上的任务完成之后,就会从任务队列中取出任务来执行,
话术
浏览器中的EventLoop(这个比较偏理论一点,我是这样理解的):js是单线程的,一次只能做一件事。js在浏览器这个宿主环境中运行。浏览器是多线程的,用户交互,定时器,网络请求等等浏览器中的事件会产生对应的任务,任务多了要在任务队列中排队,浏览器的主线程依次取出任务来执行,此过程不断重复从而形成一个循环,称为eventLoop。
概念_微任务和宏任务
异步任务
不是马上执行,是放入到队列中等待;
如果所有的任务都要按序等待,那么也不行,需要有一个能插队的机制。所以又将异步任务分为微任务和宏任务,同时对应微任务队列和宏任务队列。
当主线程空闲时,先执行微任务队列中的任务,再去执行宏任务队列中的任务。
微任务队列和宏任务队列
微任务代码(js语法)
-
Promise对象.then()
(.then( )里面的是微任务)
宏任务代码(宿主环境)
-
script
-
dom事件
-
ajax
-
setTimout
经典面试题
<script> console.log(1); setTimeout(() => { console.log(2); }, 0) console.log(3); </script> <script> console.log(4); setTimeout(() => { console.log(5); }, 0) console.log(6); </script>
<script> async function async1 () { console.log('1'); await async2(); console.log('2'); } async function async2 () { console.log('3'); } console.log('4'); setTimeout(function () { console.log('5'); }, 0); async1(); new Promise(function (resolve) { console.log('6'); resolve(); }).then(function () { console.log('7'); }); console.log('8'); </script>
4 1 3 6 8 2 7 5
<script> console.log(1); async function fnOne() { console.log(2); await fnTwo(); // 右结合先执行右侧的代码, 然后等待 console.log(3); //await等于promis // new Promise((resolve,reject)=>{ // fnTwo() // console.log(3); // }) } async function fnTwo() { console.log(4); } fnOne(); setTimeout(() => { console.log(5); }, 2000); let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码 console.log(6); resolve(); console.log(7); }) setTimeout(() => { console.log(8) }, 0) p.then(() => { console.log(9); }) console.log(10); </script> <script> console.log(11); setTimeout(() => { console.log(12); let p = new Promise((resolve) => { resolve(13); }) p.then(res => { console.log(res); }) console.log(15); }, 0) console.log(14); </script>
6 7 10 3 9 11 14 8 12 15 13 5