AJAX
浅谈AJAX
一、ajax初步
AJAX
- Asynchronous javascript and xml 异步的 javascript 和 xml
- 数据都是存储数据库中的。而服务端通过服务端的技术(nodejs、php、java、python…)把数据从数据库中读取出来再处理成客户端需要的数据,然后通过网络技术(ajax、jsonp 等)把数据传递给客户端;
ajax 四步
第一步:创建一个ajax对象
var xhr = new XMLHttpRequest();
第二步:调用ajax对象的open方法设置请求信息:
xhr.open('GET', './data.json', false);
参数详解:
- 请求方式 http method(GET POST PUT DELETE OPTIONS…)
- 请求的服务端 url 地址(接口)
- 同步或异步 true 表示同步,false 表示异步
第三步:设置xhr的onreadystatechange事件监听
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 当xhr.readyState变成4 并且 xhr 的 status 为200时表示当前请求成功
// 当成功后,xhr 的 responseText 属性会存储着本次请求获取的数据
console.log(xhr.responseText);
}
};
第四步:发送请求
xhr.send();
jequry的AJAX
// ajax 方法是 jQ 的静态方法;ajax 定义在 jQ 自己身上,没有定义在原型上,只有 jQuery 自己能调用
$.ajax({
url: 'json/data.json', // 接口
method: 'GET', // http method 请求方式,默认'GET'
async: true, // 是否异步,默认值 true,表示异步;
dataType: 'json', // 数据类型,因为 jq 的 ajax 帮我们格式化数据,所以告诉它数据类型
data: {
id: '17',
price: 1000
}, // POST 请求的参数,是发送给服务器的数据
success (data) {
// 如果 ajax 请求成功会调用这个函数;这个 data 就是请求回来的数据,并且jq会帮我们处理成对象,不
// 用我们再 JSON.parse()
console.log(data);
},
error (err) {
// 如果 ajax 请求失败,会调用这个函数
console.log(err);
}
});
---------------------------------------------------------------
let send = () => {
//请求数据并绑定
$.ajax({
url: "banner.json", //请求路径
type: "get",
async: false,
success: function (data) {
bindHtml(data);
timer = setInterval(autoMove, 2000)
changeTip();
}
})
}
二、数据绑定
- 页面中的数据通常都不是写死的,大多数情况下都需要动态绑定数据;
let ul = document.getElementById('ul');
var ary = [
{
name: '张三',
age: 18
},
{
name: '李四',
age: 19
},
{
name: '王五',
age: 20
}
];
1. 创建元素
利用动态创建 DOM 的方法,动态创建 dom 对象
for (let i = 0; i < ary.length; i++) {
let cur = ary[i];
let newLi = document.createElement('li');
newLi.innerHTML = 'name: ' + cur.name + ' age:' + cur.age;
ul.appendChild(newLi); // 所以在这里每次都插入一个新元素,就会引发一次 DOM 回流,性能开销很大,
// 不推荐这种做法
}
- DOM回流(reflow): 在页面中某个元素的插入、删除、位置、大小发送变化,那么会重新计算其他元素的位置,这样做非常消耗性能;
- DOM重绘(repaint):当页面中的元素的背景、字体颜色发送改变、那么浏览器需要对其进行重新绘制,这种现象称为重绘;
2. 利用文档碎片
文档碎片:一个通过 DOM api 创建的临时存放 DOM 元素的容器
let frg = document.createDocumentFragment(); // 创建文档碎片
for (let i = 0; i < ary.length; i++) {
let cur = ary[i];
let newLi = document.createElement('li');
newLi.innerHTML = 'name: ' + cur.name + ' age:' + cur.age;
frg.appendChild(newLi);
}
ul.appendChild(frg);
frg = null; // 当插入后,手动释放 frg 的内存(手动释放临存储对象的内存是一种优秀的编程习惯)
3. 拼接字符串+innerHTML(元素对象的innerHTML可以识别字符串中的html标签)
let str = '';
for (let i = 0; i < ary.length; i++) {
let cur = ary[i];
str += '<li>' + 'name: ' + cur.name + 'age: ' + cur.age + '</li>';
}
console.log(str);
ul.innerHTML = str;
4. 模板字符串
let tpl = ``;
for (let i = 0; i < ary.length; i++) {
let cur = ary[i];
tpl += `<li>
<strong>name: ${cur.name}</strong>
<strong>age: ${cur.age}</strong>
</li>`
}
ul.innerHTML = tpl;
AJAX深入理解
一、什么是AJAX
ajax: async javascript and xml 异步的 js 和 xml,此处的异步指的是:局部刷新(对应的是全局刷新)
ajax : 是一种前后端数据交互的技术;
前后端同时进行开发项目;数据交互;接口文档:url 请求方式,参数,返回的数据类型,返回数据格式;
1. 服务器端如何渲染
当服务器接收到请求后:
- 找到对应的页面,获取到页面的代码
- 根据需求从数据库中获取到需要动态展示的数据
- 把页面和数据混合在一起进行渲染,生成有结构有内容的完整页面
- 把渲染完的页面返回给客户端
2. 客户端如何渲染
当服务器接收到请求后,把需要的页面代码返回给客户端,而第一次渲染完只有结构和样式没有数据,服务器获取到数据请求后,把数据找到,返回给客户端,然后客户端把获取的数据展示在页面中,这就是异步的 js 区域页面局部刷新。
3. 服务器渲染的的特点
- 我们看到的内容都是在服务器端渲染的(JSP / PHP / ASP / ASP.NET / NODE…)客户端只是把所有渲染好的内容呈现在页面中而已,然而我们第一次渲染完,页面中的某部分数据需要更新了,我们需要让服务器整体重新的渲染一次(包含最新的数据),把最新的页面返回给客户端,客户端只能整体刷新页面展示最新的内容 -> 全局刷新性能和体验等都非常的差,而且服务器压力也很大
- 如果服务器性能比较高,页面呈现出来的速度会快一些,因为只要从服务器拿到内容,一切信息都已经准备好了
- 由于内容在服务器端就已经渲染好了,所以页面渲染完成后,在页面的源代码中都可以看到内容,有利于 SEO 搜索引擎优化
4. 客户端渲染数据内容特点
- 可以实现页面中内容局部刷新,而且渲染的操作交给客户端来做 -> 体验好,减轻了服务器的压力
- 而且开始可以只把部分区域的数据获取到,滚动到某个区域后,再请求对应的数据也可以,实现数据的分批异步加载,提高性能体验
- 由于客户端渲染的内容没有出现在页面的源代码中, 不利于 SEO 优化。
二、当代项目开发的整个架构模型
- 纯服务器渲染(需要做 SEO 优化或者是技术氛围问题)-> 不推荐
- 混编模式:部分内容是服务器渲染,部分内容是客户端渲染 -> 常见的
- 骨架屏:首屏内容都是服务器渲染的,目的是让页面一打开就能把首屏内容加载出来。其余屏都是 AJAX 逐一获取的,对于表单提交等数据交互操作也是客户端为主(局部刷新)
- 完全客户端和服务器端分离开发 -> 目前最常见的(推荐)
- Vue / react / jQuery
- 把 Vue 和 react 在服务器端基于 node 来渲染 -> 服务器端渲染
三、什么是xml
XML:可扩展的标记语言,用自己定义的标签来储存数据的(在很早以前,我们基于 Ajax 和服务器我们基于 AJAX 和服务器进行交互的数据格式一般都已 XML 格式为主,因为它能清晰展示出对应的数据和结构层级;但是到后面,流行了一种新的数据格式 JSON,它不仅比 XML 更清晰展示数据的结构,而且同样的数据存储,JSON 更加轻量,也方便解析和相关的操作,所以现在前后端的数据交互都已 JSON 格式为主)
四、Ajax的基础操作
- 创建 Ajax 实例
let xhr = XMLHttpRequest;
但是 ie 低版本浏览器中用的是 new ActiveXObject() 高程3中 js 惰性编程思想,关于 xhr 的兼容处理
- 打开 url (配置发送请求的信息)
xhr.open('GET','/json/xxx.json','true')
第一个参数:HTTP 请求方式
第二个参数:URL 请求地址 (api 接口地址)
第三个参数:ASYNC:设置同步或者异步,默认true 是同步,false 是异步
第四个参数:USER-NAME:传递给服务器的用户名
第五个参数:USER-PASS:传递给服务器的密码
- 监听 Ajax 状态,在状态为/^\d&/的时候,获取服务器响应的内容
xhr.onredaystatechange = function () {
if (xhr.readyState === 4 && /^(2|3)\d{2}&/.test(xhr.status)) {
let result = xhr.responseText;
}
}
- 发送请求
xhr.send(null);
send 中放的是请求主体内容
Ajax 任务发送请求到服务器,从服务器获取到相应的内容,从 send 后开始,到 xhr.readystate === 4 的时候算任务结束
ajax基础
$.ajax({
url:"",
type:"post",
data:{
userName:a.value,
passWord:b.value
},
success:function(data){
// 当请求成功,会执行此函数
//{}
if(data.status===0){
// 请求成功
}else if(data.status==1){
//该用户未注册
}else if(data.status==2){
// 密码输入错误
}
}
})
// ajax axios fetch $.ajax({});
// typeScript fluter
// axios.get("data.json").then(function(data){
// });
ajax的readstate
// script的src img的src link 浏览器的url地址栏; ajax
// XMLHttpRequest 是一个内置的类;
//1. 创建了一个ajax的实例;
let xhr = new XMLHttpRequest;
console.log(xhr.readyState);
//2.请求方式,请求路径,同步异步;
xhr.open("get","11.html",false);
console.log(xhr.readyState);
//3.监听readystate发生改变的方法;
xhr.onreadystatechange=function(){
// 如果是同步,只输出4;如果是异步会输出2 3 4;
// 如果是同步,如果请求不完,不会执行这个回调,但是readyState也会发生2-->3-->4的变化,
只是不能执行而已;等上面执行完,那么readyState已经变成了4;所以只会输出结果4;
// readyState不同,说明请求进行到了不同的阶段;
//console.log(xhr.readyState);
if(xhr.readyState===4&&/^2\d{2}/.test(xhr.status)){
// 说明数据已经传输到了客户端
}
}
//4.发送请求
xhr.send();
// xhr.readyState : 0 1 2 3 4;代表了ajax不同的实例状态;
// readyState :代表了该请求进行到了不同的阶段;
// 0 : 创建ajax实例成功;
// 1 : 确定好了请求的方式,请求的路径以及同步异步;
// 2 : 服务器已经接受到了客户端的请求,并且把响应头传给了客户端;
// 3 : 服务器正在向客户端发送数据
// 4 :客户端全部接受到了数据,那么状态变成4;
ajax的状态码
let xhr = new XMLHttpRequest;
console.log(xhr.readyState);
//2.请求方式,请求路径,同步异步;
xhr.open("get","11.html",false);
console.log(xhr.readyState);
//3.监听readystate发生改变的方法;
xhr.onreadystatechange=function(){
if(xhr.readyState===4&&/^2\d{2}/.test(xhr.status)){
}
}
//4.发送请求
xhr.send();
// 1.readyState
// 2.status : 都是xhr这个实例上的一个属性名,当这个实例的请求操作进行到不同阶段时,
会不断更改readyState;当请求回来以后,这个请求就会更改这个实例的status,来表示该请求的结果;
// 200 : 成功
// 301 : 永久重定向 ;将域名重定向一个新的域名上;
// 304 : 有缓存
// 307: 临时转移
// 400 : 报文存在语法错误
// 401 : 请求需要验证
// 403 :没有权限访问
// 404 : 路径错误
// 500 : 服务器的未知错误
// 503: 超负荷;当用户的访问量超过服务器承受的最大用户量;负载均衡【node】
ajax的请求方式
<script>
let xhr = new XMLHttpRequest;
console.log(xhr.readyState);
//2.请求方式,请求路径,同步异步;
xhr.open("post","11.复习.html",false);
//3.监听readystate发生改变的方法;
xhr.onreadystatechange=function(){
if(xhr.readyState===4&&/^2\d{2}/.test(xhr.status)){
}
}
//4.发送请求
xhr.send({username:"aaa"});
// 前端: 请求头请求体
// 后端: 响应头响应体
//重点
// 1. get : 一般用于获取数据(获取订单、获取所有用户)
// 1): get请求传参通过地址栏传参,把数据拼接到url问号的后面
// 2): 各个浏览器对地址栏url大小由要求,不可以无限传参;IEurl控制4Kb
// 3): 直接将数据暴露在地址栏上,安全性较低
// 4): get请求会走缓存,如果不想走缓存,在url的后面拼接一个随机的时间戳;
// 2. post :一般用于向服务器发送数据(登录,注册,提交订单...)
// 1) : post传递数据是放到请求体中,传递给服务器
// 2) :数据大小没有要求
// 3) : 存放在请求体中,安全系数高
// 4) : post请求不走缓存
// delete : 删除操作
// head
// put
$.ajax({
url:"data.json",
type:"get",// 如果不传参数,默认会走get请求
data:{username:11,password:22},
async:false,// 如果不写,默认是异步
//cache:false,// 默认会走缓存,如果是false,是不走缓存的
success:function(data){
// data: JSON格式的对象;
},
error:function(){
// 如果请求失败,会执行这个函数
}
})
</script>
五、HTTP的请求方式
不论是 GET 和 POST 都可以吧信息传递给服务器,也能从服务器获取到结果,只不过是谁多谁少的问题
真实项目中用对应的请求方式,会使请求变得更加明确(语义化),不遵循这些方式也可以,最起码浏览器在语法上是允许的:但是这些是开发者们相互约定俗成的规范
本质区别:GET 系列传递给服务器信息的方式一般采用问号传参,而 POST 系列传递给服务器信息的方式一般采用设置请求主体
- GET 传递给服务器的内容比 POST 少,因为 URL 有最长大小限制(IE 浏览器一般限制 2kb ,谷歌浏览器一般限制为 4 ~ 8kb,超过长度的部分自动被浏览器截取了)
xhr.open('GET', '/list ? name = zhufeng & year = 10 & xxx = xxx...')
xhr.send('....') // 请求主体中传递的内容理论上没有大小限制,但是真实项目中,为了保证传输的速度,我们
// 会自己限制一些
- GET 会产生缓存(缓存不是自己可控制的):因为请求的地址(尤其是问好传递的信息一样),浏览器有时候会认为你要和上次请求的数据一样,拿的是上一次信息,这种缓存我们不期望有,我们期望的缓存是自己可控制的;所以真实项目中,如果一个地址,GET 请求多次,我们要去除这个缓存
// 解决办法设置随机数
xhr.open('GET', '/list ? name = zhufeng &_ = '+Math.random());
...
xhr.open('GET', '/list ? name = zhufeng &_ = '+Math.random());
- GET 相比较 POST 来说不安全,GET 是基于问号传参传递给服务器内容,有一种技术叫做 URL 劫持,这样别人可以获取或者篡改传递的信息,而 POST 基于请求主体传递信息,不容易被劫持
GET系列请求:一般用于从服务器获取信息,给的少拿得多
- GET
- DELETE 一般应用于告诉服务器,从服务器上删除点东西
- HEAD 只想要获取响应头内容,告诉服务器响应主体内容不要了
- OPTIONS 试探性请求,发个请求给服务器,看看服务器能不能收到,能不能返回
POST系列请求:一般用于给服务器推送信息,给的多拿得少 - POST
- PUT 和 DELETE 对应,一般是想让服务器把我传递的信息存储到服务器上(一般应用于文件和大型数据内容)
客户端怎么把信息传递给服务器? - 问号传参:xhr.open(‘GET’,‘getdata ? xxx = xxx & xxx = xxx’)
- 设置请求头 :xhr.setRequestHeader([key],[value])
- 设置请求主体:xhr.send(请求主体信息)
服务器怎么把信息返回给客户端?
- 通过响应头
- 通过响应主体(大部分信息都是基于响应主体返回)
1. 请求时间
xhr.timeout = 10 设置 AJAX 的等待时间,超过这个事件算 AJAX 的延迟
xhr.ontimeout = function () {} 超过请求时间做的事
xhr.abort() 手动中断 AJAX 请求
xhr.withCredentials = true 在跨域请求中允许携带证书(携带 COOKIE)
2. AJAX状态码
xhr.redayState获取状态码
0: UNSEND 未发送,创建一个 xhr,初始状态是0
1: OPENED 已经打开,执行了 xhr.open
2: HEADERS_RECEIVED 响应头信息已经返回给客户端,发送请求后,服务器会依次返回响应头和响应主体的信息
3: LOADING 等待服务器返回响应内容
4: DONE 响应主体信息已经返回给客户端
六、 jQuery中AJAX的应用
$.ajax() 基于原生 js 的 ajax 四步进行封装
- $.ajax([URL],[OPTIONS])
- $.ajax([OPTIONS]) URL在配置项中(推荐)
- $.get/post/getJSON/getScript()
1. 配置项信息(jQuery中AJAX)
url:请求的 API 接口地址
method:HTTP 请求方式,默认 GET
data:传递给服务器的信息,默认 null(可以是字符串,可以是对象,而且如果 GET 系列请求,JQ 会自动把信息拼接到 URL 的末尾,基于问号传参传递给服务器;如果是 POST 请求,JQ 会基于请求主体,把信息传递给服务器)
dataType:预设服务器返回的结果格式(服务器返回的一般都是 JSON 格式的字符串,如果我们设置了 DATA-TYPE,JQ 会根据设置的类型,把服务器返回的结果处理为对应的格式),支持的内容text / json / xml / html / script / jsonp(跨域) =>不影响服务器返回的结果,只是把服务器返回的结果进行二次处理
async:是否为异步操作,默认是 TRUE,代表异步操作
cache:缓存处理,只对 GET 系列请求有作用,默认是 TRUE 不处理缓存,当我们设置 FALSE 后,JQ 帮我们在 URL的末尾设置一个随机数
contentType:设置传递给服务器内容的格式类型 默认是"application/x-www-form-urlencoded"
客户端传递给服务器信息的格式(类型一般都是字符串),常用的:
form-data 表单数据:JSON 格式 ‘{“name”:“xxx”,“lx”:1}’
x-www-form-urlencoded:name=xxx&lx=1
raw:纯文本格式
headers:设置请求头信息,他是一个对象
timeout:设置超时的时间
success:回调函数,当数据请求成功执行,方法中的参数就是从服务器获取的结果
error:回调函数,数据请求失败执行,方法中的参数是错误信息
<script>
// $ === jQuery
// ajax都可以传递什么参数
$.ajax({
url:"data.txt",
type:"get",
async:false,// async : 同步异步,如果不写,默认是异步;
cache:false,// 默认走缓存,true是走缓存,false是不走缓存;
data:{},
dataType:"json",// 请求来的数据格式
success:function(data){
// 当请求成功执行的回调函数;并且数据传递给这个回调函数的实参;
// 默认是json格式的对象
},
error:function(){
// 请求失败执行的回调函数
},
beforeSend:function(xhr){
// 在发送请求之前,执行回调;一般用于设置请求头;
// xhr: 就是ajax的实例
xhr.setRequestHeader();
},
context:document.body,
complete:function(){
// 不管成功还是失败,都要调用这个方法;
},
timeout:1000,// 设置请求的超时时间;
username:"",
password:"",// 请求认证的用户名和密码
xhr:function(){
}
})
</script>
2. AJAX同步异步
<script>
let xhr = new XMLHttpRequest;
xhr.open("get","1.复习.html",false);// true :异步 false 同步;
xhr.onreadystatechange=function(){
console.log(xhr.readyState);
}
xhr.send();// 发送请求
console.log(100);
同步: 4 100;
异步:100 2 3 4;
同步异步的应用场景
1. 异步:
打开首页有十几个请求;如果该请求跟其他请求的数据没有关系,那么一般用异步;
2. 同步: 如果一个请求回来的数据会作为下一个请求的参数,这时第一个请求完成以后再发第二个请求,
那么第一个请求应该用同步;
JS本身是一个单线程;但是浏览器是多线程;浏览器可以同时发送处理多个请求;
能用异步就别用同步;
$.ajax({
url:"data.txt",
async:true,
success:function(data){
$.ajax({
url:"data.txt",
data:a.a,
success:function(data){
$.ajax({
})
}
})
}
})
$.ajax();// 1s
$.ajax();// 2s
$.ajax();// 3s
// 最终就需要3秒;
// promise
</script>
3.封装jequry中的AJAX的应用
function ajax(options){
// 准备一个默认的对象
let default_op={
type:"get",
async:true,
cache:true,
success:null,
data:null
}
// 循环options,给default中属性名重新赋值;
for(let key in options){
default_op[key]=options[key];
}
if(default_op.type.toLowerCase()==="get"){
// 为了解决传参;get请求需要将data的值拼到url的后面;
let str=`?`;
for(let key in default_op.data){
str+=`${key}=${default_op.data[key]}&`
}
str=str.slice(0,str.length-1);
default_op.url+=str;
if(!default_op.cache){
// 如果不走缓存,在后面添加时间戳;
default_op.url+= `&time=${Date.now()}`;
}
}
let xhr = new XMLHttpRequest;
// 取到default_op中的值;给open方法传入参数;
xhr.open(default_op.type,default_op.url,default_op.async);
xhr.onreadystatechange=function(){
if(xhr.readyState===4&&/^2\d{2}/.test(xhr.status)){
// 把请求回来的数据转成JSON格式的对象,传给success的回调;
let val = JSON.parse(xhr.responseText);
default_op.success(val);
}else if(xhr.readyState===4){
// 如果请求不成功,执行失败的回调;
default_op.error();
}
}
// 发送请求;
if(default_op.type==="get"){
default_op.data=null;
}
xhr.send(default_op.data);
}
ajax({
url:"data.txt",
type:"get",
data:{username:"a",password:"b"},
cache:false,
success:function(data){
console.log(data);
}
})
七、ajax
ajax设置请求头
<script>
// 有些请求需要通过请求头传递给后端一些数据或指责一些请求信息;请求头比请求体要早到达服务器,
服务器可以根据请求头的信息,进行相应的处理;
// 一般情况下,会将请求的cookie放在请求头中,传递给服务器;
let xhr = new XMLHttpRequest;
xhr.open("get","1.html",false);
xhr.onreadystatechange=function(){
console.log(xhr.readyState);
}
// 当真正的工作中,cookie是后端生成的;
xhr.setRequestHeader("Cookie","headertest");
// 在发送请求之前设置这些请求头的信息
xhr.send();
</script>
promise的ajax
promise : 解决异步回调地狱的一种方案;
第二个请求需要等到第一个请求成功以后才能执行,这种无限嵌套的请求就是回调地狱;
将异步的回调同步的展示出来;
$.ajax({
url:"/login",
type:"post",
success:function(data){
// data:{statusCode:0}// 这是后端返回的数据
if(data.statusCode===0){
$.ajax({
url:"/order",
type:"get",
success:function(){
}
});
}
}
});
if(pathname==="/login/list"){
// 登录
}
if(pathname==="/order"){
// 请求订单
}
let getJSON=function(str){
// promise 和 ajax实例
let promise = new Promise(function(resolve,reject){
let xhr = new XMLHttpRequest();
xhr.open("get",str,false);
xhr.onreadystatechange=function(){
if(xhr.readyState===4&&/^2\d{2}/.test(xhr.status)){
let val = JSON.parse(xhr.responseText);
resolve(val)
}else if(xhr.readyState===4){
reject()
}
}
xhr.send();
})
return promise;
// 返回一个promise的实例;
}
getJSON("data.txt").then(function(data){
console.log(data);
})
getJSON("/userList").then(function(data){
// 把promise请求回来的数据,传递给then的回调函数中的参数
return getJSON("/order")
}).then(function(data){
return getJSON("/list")
}).then(function(data){
}).catch(function(){
// 如果有任意一个请求失败,触发catch对应的回调;
})
下一篇: Python遇到的一些问题