封装一个Ajax函数
Ajax请求网络一共五个步骤,而当我们要请求很多个的时候,就需要写很多个基本一样的语句,写起来就显得较为繁琐,所以我们要来自己封装一个Ajax函数,方便我们在写网络请求的时候直接调用它
下面就是封装的一个Ajax函数,其中传入两个参数,就是网络请求的地址(url),以及对返回的数据的处理函数(cb)
function myTool(url, cb) {
// 后半部分是在做兼容处理。为了让IE的浏览器也能使用
var xhr = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP")
// 第三个参数是选择是否异步,默认为true异步,所以可写可不写
xhr.open("GET", url, true)
xhr.send()
xhr.onreadystatechange = function() {
// 只要readyState等于了4就代表网络请求成功
// 后半部分代表的是业务数据是否正确,200表示正确
if (xhr.readyState == 4 && xhr.status == 200) {
cb(xhr.responseText)
}
}
}
以上就封装好了一个函数,有需要的时候就可以直接引入文件,调用函数即可
实例
<script src="./tool.js"></script>
<button onclick="fn()">ajax请求数据</button>
<script>
function fn() {
// 引入myTool函数,将网络请求的返回数据作为函数的形参传入
myTool("/goods", function(str) {
// 将传入的数据转为JSON数据
var obj = JSON.parse(str)
// 遍历数据,并写在页面上
for (let i = 0; i < obj.data.length; i++) {
console.log(obj.data[i], 1111)
let box = document.createElement("div")
box.className = "box"
box.innerHTML = `<b>${obj.data[i].title}---${obj.data[i].des}</b>`
document.body.appendChild(box)
}
})
}
</script>
执行结果
将控制台的数据写在了页面上
利用jQuery来做上面的功能
什么是jQuery?
jQuery 是一个 JavaScript 库,它极大地简化了 JavaScript 编程,且jQuery 比较容易学习
不过由于浏览器标准越来越规范,尤其是借鉴jQuery,在新的标准中添加了很多DOM操作标准,一部分功能不用jQuery,也可以很完美简单的实现,并且浏览器对标准的支持越来越高,jQuery 作为弥补不同浏览器差异的功能,也越来越显得可有可无,ES6的标准越来越规范,ES6越来越好,我们的对于jQuery的依赖也就越来越低
很多需要jQuery来解决的问题,我们原生API都开始支持,jQuery的作用就变弱了,所以jQuery我们大概了解一下,简单的学习,就可以了
有两个版本的 jQuery 可以下载
- Production version - 用于实际的网站中,已被精简和压缩。
- Development version - 用于测试和开发(未压缩,是可读的代码)
都可以从 jquery.com 中下载。
jQuery 库是一个 JavaScript 文件,我们一般使用 HTML 的 <script>
标签引用它
不想下载并存放 jQuery,也可以通过 CDN(内容分发网络) 引用它,我就是直接引用没有下载的
jQuery是用美元符号来定义的,所以使用是用$.方法来调用
$.get() 方法通过 HTTP GET 请求从服务器上请求数据
实例
// 引入jQuery
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.2.4/jquery.js"></script>
<button onclick="fn()">ajax请求数据</button>
<script>
function fn() {
$.get("/homegoods", function(res) {
var obj = res
for (let i = 0; i < obj.data.length; i++) {
console.log(obj.data[i], 1111)
let box = document.createElement("div")
box.className = "box"
box.innerHTML = `<b>${obj.data[i].title}---${obj.data[i].des}</b>`
document.body.appendChild(box)
}
})
}
</script>
结果和上面的一模一样,这里就不在演示了
promise函数
我们在做有一些业务的时候需要先获取了数据,在将数据给到下一个函数调用,就像有我们填写地址一样,假如我是成都的,那么我在选择了四川省后,当把我选择的数据发送给后台,后台又根据我发送的数据请求新的数据发送回来,我才可以进行下一步的选择
这就相当于,我们要在一个函数里嵌套另一个函数,来完成我们的业务,就像俄罗斯套娃一样,一层叠一层
下面的函数就是一个例子,这样写的不仅看着代码混乱且难以维护,一旦有数据出错,寻找错误非常耗时费力
$.get("/sheng",(res)=>{
$.get("/sheng",(res)=>{
$.get("/sheng",(res)=>{
$.get("/sheng",(res)=>{
$.get("/sheng",(res)=>{
$.get("/sheng",(res)=>{
})
})
})
})
})
})
所以我们将使用promise函数来进行优化
<script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.2.4/jquery.js"></script>
<h1>promise</h1>
<button onclick="fn()">点击一下</button>
<script>
function fn(){
$.get("/ajax1")
.then((res1)=>{
console.log(res1)
return $.get("/ajax2")
})
.then((res2)=>{
console.log(res2)
return $.get("/ajax3")
})
.then((res3)=>{
console.log(res3)
return $.get("/ajax4")
})
.then((res4)=>{
console.log(res4)
})
}
</script>
大家自己去试一试,就会发现,它并不是一起打印出来的,而是一个一个挨着打印
为什么会这样呢?就是因为它要等上一级的函数执行完毕返回了数据给它,它才会开始执行,相当于阻塞,上一个没执行完成并返回数据下一个就不能执行
promise 这种设计在es5就已经出现了,只不过在es6中正式出现在语法里,它被设计成一个全局构造函数
这个函数创建出来的对象,是一个特殊的数据容器
这个数据容器内部有三种状态: 等待 ==>产生的正确数据以及产生了错误的数据
实例1
当我们在promise函数里面什么都不写,既不给正确数据也不给错误数据的时候就是等待状态
var p1=new Promise((resolve,reject)=>{
})
console.log(p1)
执行结果
实例2
给promise一个正确的数据
var p1=new Promise((resolve,reject)=>{
resolve('hello')
})
console.log(p1)
执行结果
实例3
给promise一个错误的数据
var p1=new Promise((resolve,reject)=>{
reject("业务出错了")
})
console.log(p1)
执行结果
以上就是promise对不同的数据,产生的不同的三种状态
要么产生正确的数据,要么产生错误的数据,总之只能有一种数据,不可以同时有两种矛盾的数据,如果一下两种数据都写了,那么也只会执行上面的一条语句
resolve('hello')
reject("业务出错了")
p1.then(cb)
then函数有一个返回值:这个返回值一定是一个新的Promise
返回的新的Promise对象 是由cb函数的返回值决定的
cb函数的返回值也是一个Promise对象 那么then函数的返回值就是它
cb函数的返回值不是一个Promise对象 那就就把cb的返回值封装为Promise对象 然后作为then的返回值
实例
产生正确数据后,调用then函数,并打印数据
var p1=new Promise((resolve,reject)=>{
resolve('hello')
})
console.log(p1)
p1.then((data)=>{
console.log(data,111)
},(err)=>{
console.log(err,222)
})
p1.then((data)=>{
console.log(data,111)
})
.catch((e)=>{
console.log(e,333)
})
执行结果
promise对象除了有then函数 还有catch 就是js基础语法中的catch,只有产生错误数据时,才会被catch函数所捕获
实例
产生正确数据后,调用then函数,并打印数据
var p1=new Promise((resolve,reject)=>{
reject("业务出错了")
})
console.log(p1)
p1.then((data)=>{
console.log(data,111)
},(err)=>{
console.log(err,222)
})
p1.then((data)=>{
console.log(data,111)
})
.catch((e)=>{
console.log(e,333)
})
执行结果
Promise函数是同步的,虽然Promise函数是同步的但是可以再次执行异步的业务
<script>
var p1 = new Promise((resv, rej) => {
console.log("1")
$.get("/ajax1", (data) => {
console.log("2--异步")
resv(data)
})
console.log("3")
})
console.log("4")
p1.then((res) => {
console.log("5")
})
console.log("6")
</script>
Promise函数是同步的,console.log()也是同步的,所以先执行console.log()进行打印1,
而$.get()要进行网络请求,需要花时间,但是这个是异步,不会阻塞下面的代码执行,
所以接下来回执行下面的console.log()打印3,4,
p1.then()要等promise函数执行完了产生了数据才会执行,所以也不会立即执行,
继续执行下面的console.log()打印6,
要先执行了$.get(),promise才算执行完产生了数据触发p1.then()执行
执行结果
什么是Axios
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
Axios的特性
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
安装Axios
npm install(i) axios
或者直接引入<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
实例
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.js"></script>
<h1>axios网络请求工具</h1>
<script>
var p1=axios('/ajax1')
p1.then((data)=>{
console.log(data.data)
return axios('/ajax2')
})
.then((data2)=>{
console.log(data2.data)
return axios('/ajax3')
})
.then((data3)=>{
console.log(data3.data)
return axios('/ajax4')
})
.then((data4)=>{
console.log(data4.data)
})
.catch((e)=>{
console.log(e)
})
</script>
执行结果
fetch
它是浏览器自带的api
fetch是一种HTTP数据请求的方式,是XMLHttpRequest的一种替代方案。fetch不是ajax的进一步封装,而是原生js。Fetch函数就是原生js,没有使用XMLHttpRequest对象
Fetch、ajax与axios的区别
传统的ajax利用的是HMLHttpRequest这个对象,和后端进行交互
而JQury ajax是对原生XHR的封装,多请求间有嵌套的话就会出现回调地狱的问题
axios使用promise封装XHR,解决了回调地狱的问题
而Fetch没有使用XHR,使用的是promise
await
使用上面的promise函数的 .then 函数来调用确实比嵌套调用方便一些,但是还不够高聚合低耦合的特性,因此我们最终优化,使用await
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身
如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果
如果该值不是一个 Promise,await 会把该值转换为已正常处理的Promise,然后等待其处理结果
如果 Promise 处理异常,则异常值被抛出
这是ES7出的新语法
let data1=await new Promise((n1,n2)=>{n1(2000)})
console.log(data1)
let data2=await axios('/ajax2')
console.log(data2)
let data3=await axios('/ajax3')
console.log(data3)
let data4=await axios('/ajax4')
console.log(data4)
await顾名思义,等一会,是一个会阻塞的函数,所以当用它的时候后面的代码就不会执行,那么就可以等他执行完毕返回的数据给到下一个要执行的函数
这样就相当于一个一个的代码块,既不需要嵌套也不需要一直点then,方便了许多