AJAX进阶


前言

  1. 区分异步代码,回调函数地狱问题和所有解决防范(Promise 链式调用)
  2. 掌握 async 和 await 使用
  3. 掌握 EventLoop 的概念

一、同步代码和异步代码

同步代码:逐行执行,需原地等待结果后,才继续向下执行

异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发回调函数传递结果

回答代码打印顺序:发现异步代码接收结果,使用的都是回调函数

const result = 0 + 1
console.log(result)
setTimeout(() => {
  console.log(2)
}, 2000)
document.querySelector('.btn').addEventListener('click', () => {
  console.log(3)
})
document.body.style.backgroundColor = 'pink'
console.log(4)

结果:1, 4, 2

按钮点击一次打印一次 3

JS 中的异步代码: setTimeout / setInterval,事件,AJAX

二、回调函数地狱和 Promise 链式调用

回调函数地狱:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
缺点:可读性差,异常无法捕获,耦合性严重,牵一发动全身

Promise 链式调用:依靠 then() 方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束。then() 回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果
好处:通过链式调用,解决回调函数嵌套问题
在这里插入图片描述

/**
 * 目标:掌握Promise的链式调用
 * 需求:把省市的嵌套结构,改成链式调用的线性结构
*/
// 1. 创建Promise对象-模拟请求省份名字
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('北京市')
  }, 2000)
})

// 2. 获取省份名字
const p2 = p.then(result => {
  console.log(result)
  // 3. 创建Promise对象-模拟请求城市名字
  // return Promise对象最终状态和结果,影响到新的Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(result + '--- 北京')
    }, 2000)
  })
})

// 4. 获取城市名字
p2.then(result => {
  console.log(result)
})

// then()原地的结果是一个新的Promise对象
console.log(p2 === p)

三、async 和 await 使用

在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值
使用 async 和 await 解决回调地狱问题

/**
 * 目标:掌握async和await语法,解决回调函数地狱
 * 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
 * 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
*/
// 1. 定义async修饰函数
async function getData() {
  // 2. await等待Promise对象成功的结果
  const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'})
  const pname = pObj.data.list[0]
  const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
  const cname = cObj.data.list[0]
  const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
  const areaName = aObj.data.list[0]


  document.querySelector('.province').innerHTML = pname
  document.querySelector('.city').innerHTML = cname
  document.querySelector('.area').innerHTML = areaName
}

getData()

四、事件循环-EventLoop

事件循环负责执行代码,收集和处理事件以及执行队列中的子任务
JavaScript 单线程(某一刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型
执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环
在这里插入图片描述

五、宏任务与微任务

ES6 之后引入了 Promise 对象, 让 JS 引擎也可以发起异步任务

异步任务划分为了

  • 宏任务:由浏览器环境执行的异步代码。例如:JS 执行脚本事件,setTimeout/setInterval,AJAX请求完成事件,用户交互事件等
  • 微任务:由 JS 引擎环境执行的异步代码。例如:Promise对象.then()的回调

宏任务和微任务具体划分:
在这里插入图片描述
在这里插入图片描述
注意:宏任务每次在执行同步代码时,产生微任务队列,清空微任务队列任务后,微任务队列空间释放!

下一次宏任务执行时,遇到微任务代码,才会再次申请微任务队列空间放入回调函数消息排队

总结:一个宏任务包含微任务队列,他们之间是包含关系,不是并列关系

JavaScript 内代码如何执行?
在这里插入图片描述
执行第一个 script 脚本事件宏任务,里面同步代码
遇到 宏任务/微任务 交给宿主环境,有结果回调函数进入对应队列
当执行栈空闲时,清空微任务队列,再执行下一个宏任务,从1再来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值