【AJAX】XMLHttpRequest、Promise 与 axios的关系
目录
一、AJAX原理 —— XMLHttpRequest
1.1 使用XMLHttpRequest
二、 XMLHttpRequest - 查询参数 (就是往服务器后面拼接要查询的字符串)
三、 地区查询
四、 XMLHttpRequest - 数据提交
五、 认识Promise
5.1 为什么 JavaScript 需要异步?
5.2 Promiss - 三种状态
5.3 使用Promiss + XHM 获取省份列表
六、 封装简易的axios——获取省份列表
七、 注册账号——支持传递请求体数据 data选项
总结不易~ 本章节对我有很大的收获,希望对你也是!!!
本节素材已上传至Gitee:https://gitee.com/liu-yihao-hhh/ajax_studyhttps://gitee.com/liu-yihao-hhh/ajax_study
一、AJAX原理 —— XMLHttpRequest
定义
XMLHttpRequest(XHR) 对象用于与服务器交互。通过XMLHttpRequst可以再不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest在AJAX编程中被大量使用。
与axios的关系: axios内部采用XMLHttpRequest 与服务器交互
1.1 使用XMLHttpRequest
- 创建XMLHttpRequest对象
- 配置请求方法和请求url地址
- 监听loadend事件,接受响应结果
- 发起请求
const xhr = new XMLHttpRequest() xhr.open(\'请求方法\', \'请求url网址\') xhr.addEventListener(\'loadend\', () => { // 接受 - 响应结果 console.log(xhr.response) }) // 发送 - 请求 xhr.send()
XMLHttpRequest基础使用,获取服务器的数据并展示
// 1. 创建一个XMR对象 const xhr = new XMLHttpRequest() // 2. 配置请求方法和请求url地址 xhr.open(\'GET\', \'http://hmajax.itheima.net/api/province\') // 3. 监听 loadend事件 接收响应结果 xhr.addEventListener(\'loadend\', () => { console.log(xhr.response) // 这里返回的是json字符串 // json字符串转对象 const data = JSON.parse(xhr.response) console.log(data.list.join(\'
\')) // 数组转字符串进行拼接 document.querySelector(\'.my-p\').innerHTML = data.list.join(\'
\') }) // 4. 发起请求 xhr.send()
二、 XMLHttpRequest - 查询参数 (就是往服务器后面拼接要查询的字符串)
定义: 浏览器提供给服务器的额外信息, 让服务器返回浏览器想要的数据
/** * 目标:使用XHR携带查询参数,展示某个省下属的城市列表 */ const xhr = new XMLHttpRequest() // 进行查询 往服务器后面进行拼接查询的参数名 ?pname= xhr.open(\'GET\', \'http://hmajax.itheima.net/api/city?pname=辽宁省\') // loadend 加载结束事件 xhr.addEventListener(\'loadend\', () => { console.log(xhr.response) const data = JSON.parse(xhr.response) console.log(data.list) document.querySelector(\'.city-p\').innerHTML = data.list.join(\'
\') }) xhr.send()
三、 地区查询
这一个案例就是要我们同时传入两个参数,但是我们不方便自己获取两个参数后拼接到url后面,这个时候,我们就可以采用浏览器内置的构造函数URLSearchParams 来创建一个对象,里面放入我们需要传入URL的对象参数,他就会自动给我们返回一个url编码的字符串,我们就可以直接在url后面进行拼接 ?+编码即可
/** * 目标: 根据省份和城市名字, 查询对应的地区列表 */ // 1. 给查询按钮绑定一个点击事件 document.querySelector(\'.sel-btn\').addEventListener(\'click\', () => { // 2. 收集省份和城市名字 const pname = document.querySelector(\'.province\').value const cname = document.querySelector(\'.city\').value // 3. 组织查询参数字符串 const qObj = { pname, cname } // 查询参数对象 -》 查询参数字符串 // 浏览器内置的构造函数 // 1. 创建 URLSearchParams 对象 自动将我们需要的多个查询对象转换成一个字符串 好方便后续的拼接 const paramsObj = new URLSearchParams(qObj) const queryString = paramsObj.toString() console.log(queryString) // 拿到一个url编码 pname=%E6%B9%96%E5%8C%97&cname=%E6%AD%A6%E6%B1%89%E5%B8%82 // 4. 使用XHR对象, 查询地区列表 const xhr = new XMLHttpRequest() xhr.open(\'GET\', `http://hmajax.itheima.net/api/area?${queryString}`) // loadend 加载结束事件 xhr.addEventListener(\'loadend\', () => { console.log(xhr.response) const data = JSON.parse(xhr.response) console.log(data) const htmlStr = data.list.map(item => { return `${item} ` }) console.log(htmlStr) const html = htmlStr.join(\'
\') document.querySelector(\'.list-group\').innerHTML = html }) xhr.send() })
四、 XMLHttpRequest - 数据提交
需求: 通过XHR提交用户名和密码,完成注册功能
核心: 请求头设置Content-Type:application/json
请求体携带JSON字符串
提交数据就是在xhr.send()中进行提交,但是要提前设置请求头,告诉服务器我们提交的数据是JSON数据
xhr.setRequestHeader(\'Content-Type\', \'application/json\')
准备好要进行提交的数据之后,就将该数据转换成JSON字符串直接进行提交即可!
/** * 目标:使用xhr进行数据提交-完成注册功能 */ // 后端的数据提交 http://hmajax.itheima.net/api/register // 请求参数 body application/json document.querySelector(\'.reg-btn\').addEventListener(\'click\', () => { const xhr = new XMLHttpRequest() xhr.open(\'POST\', \'http://hmajax.itheima.net/api/register\') xhr.addEventListener(\'loadend\', () => { console.log(xhr.response) }) // 设置请求头 - 告诉服务器内容类型(JSON字符串) xhr.setRequestHeader(\'Content-Type\', \'application/json\') // 准备提交的数据 const userObj = { username: \'我是hhhhha\', password: \'11111111\' } const userStr = JSON.stringify(userObj) console.log(userStr) // 设置请求体 发送请求 xhr.send(userStr) })
五、 认识Promise
定义: Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值
-
同步方式:你站在门口等外卖员送来,什么事都不干,一直等着。
-
异步方式:你点完外卖,继续干别的事(比如学习/打游戏),等外卖来了,电话通知你,然后你去取。
5.1 为什么 JavaScript 需要异步?
因为 JavaScript 是 单线程的(同一时间只能做一件事),如果你在执行一个耗时操作(比如网络请求、读取大文件),同步写法会卡住整个页面,用户无法点击、无法操作,非常糟糕。异步写法可以把“耗时的事”交给浏览器处理,不阻塞主线程,页面流畅运行
Promise语法
// 1. 创建Promise对象 const p = new Promise((resolve, reject) => { // 2. 执行异步任务 并传递结果 // 成功调用: resolve(值) 触发then()执行 // 失败调用: reject(值) 触发catch()执行 }) // 3. 接收结果 p.then(result => { // 成功 }).catch(error => { // 失败 })
学了Promise后, 会更好的理解axios , 能够解决回调函数地狱的问题
创建Promise对象后传入的两个参数都是函数,但是二者分别是表示成功时调用的函数 和 失败时调用的函数,等待定时器异步操作完成后,屏幕会输出函数传入的字符
// 1. 创建Promise对象 // 参数名类型作用 // resolve函数表示成功时调用,用来传递“成功的结果” // reject函数表示失败时调用,用来传递“失败的原因” const p = new Promise((resolve, reject) => { // 2. 执行异步操作 setTimeout(() => { resolve(\'模拟AJAX请求-成功的结果\') // reject(new Error(\'模拟AJAX请求-失败的结果\')) }, 2000) }) // 3. 获取结果 p.then(result => { console.log(result) }).catch(error => { console.log(error) })
5.2 Promiss - 三种状态
一个Promiss对象,必然处于一下的一种状态:
待定(pending) new Promiss(): 初始状态, 既没有被兑现,也没有被拒绝
已兑现(fulfilled) .then(回调函数):意味着,操作成功完成
已拒绝(rejected) .catch(回调函数): 意味着操作失败
请求成功时,是fulfilled状态,触发.then()
请求失败时,是rejected状态, 触发.catch()
5.3 使用Promiss + XHM 获取省份列表
当发送请求错误的时候 将error.message错误信息渲染到屏幕上
六、 封装简易的axios——获取省份列表
通过myAxios传入的对象参数进行接收,默认是GET选项
- 创建Promise对象
- 发起XHR请求,默认是GET
- 进行xhr.open设置请求方法和地址,来为发送请求做准备
- loadend 是在请求完成后触发,来进行发挥成功或者失败的函数
- xhr.status 是服务器响应状态,xhr.response 是服务器响应内容
- xhr.send()正式发起请求到服务器
/** * 目标:封装_简易axios函数_获取省份列表 * 1. 定义myAxios函数,接收配置对象,返回Promise对象 * 2. 发起XHR请求,默认请求方法为GET * 3. 调用成功/失败的处理程序 * 4. 使用myAxios函数,获取省份列表展示 */ // 1. 定义myAxios函数,接收配置对象,返回Promise对象 function myAxios(config) { return new Promise((resolve, reject) => { // 2. 发起XHR请求 默认是get const xhr = new XMLHttpRequest() // open 设置请求的方法和地址,为发送请求做准备 xhr.open(config.method || \'GET\', config.url) // loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。 xhr.addEventListener(\'loadend\', () => { // 3. 调用成功 / 失败 \\ // xhr.response 是服务器响应的内容。 if (xhr.status >= 200 && xhr.status { console.log(result) document.querySelector(\'.my-p\').innerHTML = result.list.join(\'
\') }).catch(error => { console.log(error) document.querySelector(\'.my-p\').innerHTML = error.message })
修改myAxios函数,支持传递查询参数,就是需要传入params选项
// 判断 有 params 选项, 携带查询参数 if (config.params) { // 使用URLSearchParmas转换 并携带到url上 const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() console.log(paramsObj) console.log(queryString) // 把查询数字字符串 拼接到url?后面 config.url += `?${queryString}` console.log(config.url) }
起到查询作用就是要根据上面学习的URLSearchParams浏览器内置函数来将用户传入的params查询参数对象转换成字符串来坪街道url?后面
- 判断是否携带params对象参数
- 使用 URLSearchParams转换 并携带到url上 此时还是一个对象关系
- 将paramsObj转换成字符串queryString
- 进行与url拼接
/** * 目标:封装_简易axios函数_获取省份列表 * 1. 定义myAxios函数,接收配置对象,返回Promise对象 * 2. 发起XHR请求,默认请求方法为GET * 3. 调用成功/失败的处理程序 * 4. 使用myAxios函数,获取省份列表展示 */ // 1. 定义myAxios函数,接收配置对象,返回Promise对象 function myAxios(config) { return new Promise((resolve, reject) => { // 2. 发起XHR请求 默认是get const xhr = new XMLHttpRequest() // 判断 有 params 选项, 携带查询参数 if (config.params) { // 使用URLSearchParmas转换 并携带到url上 const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() console.log(paramsObj) console.log(queryString) // 把查询数字字符串 拼接到url?后面 config.url += `?${queryString}` } console.log(config.url) // open 设置请求的方法和地址,为发送请求做准备 xhr.open(config.method || \'GET\', config.url) // loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。 xhr.addEventListener(\'loadend\', () => { // 3. 调用成功 / 失败 \\ // xhr.response 是服务器响应的内容。 if (xhr.status >= 200 && xhr.status { console.log(result) document.querySelector(\'.my-p\').innerHTML = result.list.join(\'
\') }).catch(error => { console.log(error) document.querySelector(\'.my-p\').innerHTML = error.message })
七、 注册账号——支持传递请求体数据 data选项
// 判断是否有data选项 携带请求体 if (config.data) { // 数据转换类型 在send中发送 const jsonStr = JSON.stringify(config.data) // 请求体数据类型标记 xhr.setRequestHeader(\'Content-Type\', \'application/json\') xhr.send(jsonStr) } // 正式发起请求,把配置好的 XHR 请求发送到服务器。 else xhr.send() })
- 提交数据到服务器,用POST方法进行提交,然后携带data对象数据
- 要将data对象数据转换成JSON字符串
- 标记数据传输到服务器的数据类型是json格式
- 然后正式发起请求 xhr.send(josnStr)
/** * 目标:封装_简易axios函数_获取省份列表 * 1. 定义myAxios函数,接收配置对象,返回Promise对象 * 2. 发起XHR请求,默认请求方法为GET * 3. 调用成功/失败的处理程序 * 4. 使用myAxios函数,获取省份列表展示 */ // 1. 定义myAxios函数,接收配置对象,返回Promise对象 function myAxios(config) { return new Promise((resolve, reject) => { // 2. 发起XHR请求 默认是get const xhr = new XMLHttpRequest() // 判断 有 params 选项, 携带查询参数 if (config.params) { // 使用URLSearchParmas转换 并携带到url上 const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() console.log(paramsObj) console.log(queryString) // 把查询数字字符串 拼接到url?后面 config.url += `?${queryString}` } console.log(config.url) // open 设置请求的方法和地址,为发送请求做准备 xhr.open(config.method || \'GET\', config.url) // loadend 是在 请求完成 (不管成功还是失败)时触发的事件,用来统一处理响应结果。 xhr.addEventListener(\'loadend\', () => { // 3. 调用成功 / 失败 \\ // xhr.response 是服务器响应的内容。 if (xhr.status >= 200 && xhr.status { // 4. 使用myAxios函数 获取省份列表 myAxios({ url: \'http://hmajax.itheima.net/api/register\', method: \'POST\', data: { username: \'wshhaaaaa12w~\', password: \'1234567\' } }).then(result => { console.log(result) }).catch(error => { console.log(error) }) })
八、 天气预报案例
一些渲染操作都是非常简单的,就最后一步原生js 响应式输入,只要得到了当前的输入框,然后add~input就能做到响应式!!!
document.querySelector(\'.search-city\').addEventListener(\'input\', e => { console.log(e.target.value)})
/** * 目标1:默认显示-北京市天气 * 1.1 获取北京市天气数据 * 1.2 数据展示到页面 */// 获取并渲染城市天气函数const getWeather = async (cityCode) => { // 获取天气数据 const response = await axios(\'http://hmajax.itheima.net/api/weather\', { params: { city: cityCode } }) console.log(response.data) const data = response.data.data // 展示数据 document.querySelector(\'.dateShort\').innerHTML = data.date document.querySelector(\'.dateLunar\').innerHTML = data.dateLunar document.querySelector(\'.area\').innerHTML = data.area // 当天的气温 const nowWStr = ` ${data.temperature} ° ${data.psPm25} ${data.psPm25Level} -
${data.weather} - ${data.windDirection}
- ${data.windPower}
` document.querySelector(\'.weather-box\').innerHTML = nowWStr // 当天的天气 const twObj = data.todayWeather const todayWStr = ` 今天: ${twObj.weather} ${twObj.temNight} - ${twObj.temDay} ℃ - 紫外线 ${twObj.ultraviolet}
- 湿度 ${twObj.humidity}%
- 日出 ${twObj.sunriseTime}
- 日落 ${twObj.sunsetTime}
最后获得城市的code值优化,只需要在渲染的同时加上自定义data-code属性就好!
const cityStr = response.data.data.map(item => { return `${item.name} ` }).join(\'\') document.querySelector(\'.search-list\').innerHTML = cityStr document.querySelector(\'.search-list\').addEventListener(\'click\', e => { console.log(e.target.dataset.code) getWeather(e.target.dataset.code) })