客户端与服务器的链接请参考https://juejin.im/post/5d8088c7e51d453b39774443javascript
async javascript and xml : 异步的JS和XML;html
此处的异步指的是:局部刷新(对应的是全局刷新);java
XML : 可扩展的标记语言,用本身定义的标签来存储数据的ajax
在很早之前,咱们基于AJAX和服务器进行交互的数据格式通常都是以XML格式为主,由于它可以清晰的展现出对应的数据和结构层级;编程
但后来随着JSON数据格式的到来, 它不只比XML更清晰展现数据的结构,并且一样的数据存储,JSON更加轻量,也方便解析和相关的操做,因此如今先后端的数据交互都以JSON格式数据为主;json
// ===XML===

<?xml version="1.0" encoding="UTF-8"?>
<root> <student> <name>张三</name> <age>25</age> <score> <english>95</english> </score> </student> <student> <name>张三</name> <age>25</age> </student> <student> <name>张三</name> <age>25</age> </student> </root>
//===JSON===
[{
"name": "张三",
"age": 25,
"score": {
"english": 95
}
}, {
"name": "张三",
"age": 25
}, {
"name": "张三",
"age": 25
}]
复制代码
那咱们接下来先来看看所有刷新和局部刷新后端
1.全局刷新api
2.局部刷新 跨域
3.当代项目开发的整个架构模型浏览器
let xhr = new XMLHttpRequest;
// IE低版本浏览器中用的是new ActiveXObject(),
能够看看高程中JS惰性编程思想,关于XHR的兼容处理;
复制代码
* method: HTTP请求方式
* url: 请求地址(API接口地址)
* async : 设置同步或者异步,默认是TRUE异步,FALSE同步
* user-name: 传递给服务器的用户名;
* user-pass: 传递给服务器的密码;
xhr.open('GET','./json/xxx.json',true); // 默认异步
复制代码
// 监听AJAX的状态,在状态为xxx的时候,获取服务器响应的内容;
// AJAX状态码:0 1 2 3 4
// 当HTTP状态码为2或者3开头,而且AJAX状态码为4时,获取响应内容;
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && /^(2|3)\d{2}$/.test(xhr.status)){
let result = xhr.responseText; // =>响应内容
}
}
=> AJAX 状态码
`xhr.readyState` 获取状态码
* unsend 0 :未发送(建立一个XHR,初始状态是0)
* opend 1 : 已经打开(执行了xhr.open);
* headers_received 2 : 响应头信息 已经返回给客户端(发送请求后,服务器会一次返回响应头和响应主体的信息)
* loading 3 :等待服务器返回响应内容
* done 4: 响应主体信息已经返回给客户端
复制代码
send中放的是请求主体的内容;
//SEND中放的是请求主体的内容
xhr.send(null);
复制代码
AJAX任务:发送一个请求给服务器,从服务器获取到对应的内容,从send后开始,到xhr.readystate === 4 的时候算任务结束;
=> 真实项目中用对应的请求方式,会使请求变得更加明确(语义化),不遵循这些方式也能够,最起码浏览器在语法上是容许的;可是这些是开发者们相互约定俗称的规范
GET系列通常用于从服务器获取信息,POST系列通常用于给服务器推送信息,可是不论GET和POST均可以把信息传递给服务器,也能从服务器获取到结果,只不过是谁多谁少的问题
客户端怎么把信息传递给服务器?
服务器怎么把信息返回给客户端?
GET系列传递给服务器信息的方式通常采用:问号传参 POST系列传递给服务器信息的方式通常采用:设置请求主体
1.GET传递给服务器的内容比POST少,由于URL有最长大小限制(IE通常限制2KB,其他浏览器通常限制4-8K,超过长度的部分自动被浏览器截取了)
xhr.open('GET','/list?name=lanlan&age=17...');
xhr.send('...') // 请求主体中传递的内容理论上没有大小限制,
// 可是真实项目中,为了保证传输的速度,咱们会本身限制一些
复制代码
2.GET会产生缓存(缓存不是本身可控制的),由于请求的地址(尤为是问号传参的信息同样),浏览器有时候会认为你要和上次请求的数据同样,拿的是上一次信息; 这种缓存咱们不指望有,咱们指望的缓存是本身可控的,因此真实项目中,若是一个地址,GET请求屡次,咱们要去除这个缓存
xhr.open('GET','/list?name=lanlan&age=17...');
xhr.open('GET','/list?name=lanlan&age=17...');
**解决办法设置随机数或者时间戳**
xhr.open('GET','/list?name=lanlan&age=17...'+Math.random());
xhr.open('GET','/list?name=lanlan&age=17...'+Math.random());
复制代码
3.GET相比较POST来讲不安全: GET是基于问号传参传递给服务器内容,有一种技术叫作URL劫持,这样别人能够获取或者篡改传递信息;而POST基于请求主体传递信息,不容易被劫持;
xhr.response / xhr.responseText / xhr.responseXML
xhr.status / xhr.statusText
xhr.timeout
xhr.withCredentials
xhr.abort()
xhr.getAllResponseHeaders()
xhr.getResponseHeader([key])
xhr.open()
xhr.overrideMimeType()
xhr.send()
xhr.setRequestHeader()
一些简单方法的使用;
let xhr = new XMLHttpRequest;
console.log(xhr.readyState); //=>0
xhr.open('GET', 'json/data.json');
// console.log(xhr.readyState); //=>1
xhr.onreadystatechange = function () {
// console.log(xhr.readyState); //=>2 3 4
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 2) {
//=>获取响应头信息
//获取的服务器时间是标准的日期格式对象(GMT格林尼治时间)
//new Date()能把格林尼治时间转换为北京时间
let serverTime = xhr.getResponseHeader('Date');
// console.log(new Date(serverTime));
}
if (xhr.readyState === 4) {
//=>获取响应主体信息:咱们通常用responseText,由于服务器返回的信息通常都是JSON格式的字符串,若是返回的是XML格式,咱们用responseXML...
// xhr.responseXML
// xhr.response
// xhr.responseType
// console.log(xhr.responseText);
}
}
xhr.send(null);
// ====setTimeout===
let xhr = new XMLHttpRequest;
xhr.timeout = 1; //=>设置AJAX等待时间,超过这个时间算AJAX延迟
xhr.ontimeout = function () {
console.log('请求超时~~'); //若是超过期间就会输出;
xhr.abort(); //=>手动中断AJAX的请求
}
xhr.withCredentials = true; //=>在跨域请求中是否容许携带证书(携带COOKIE)
xhr.open('GET', 'json/data.json');
xhr.send();
// 设置请求头
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
xhr.setRequestHeader('AAA', '蓝蓝');
// Uncaught TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString. //`设置的请求头信息值不能是中文 能够经过encodeURIComponent解码
xhr.setRequestHeader('AAA', encodeURIComponent('蓝蓝'));
xhr.onreadystatechange = function () {
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 4) {
console.log(xhr.getRequestHeader);
}
}
xhr.send(null);
复制代码
//=>AJAX任务的异步
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
//=>设置事件绑定以前状态1
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>2 3 4
}
xhr.send(null);
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
xhr.send(null);
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>2 3 4
}
//=>AJAX的同步
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json', false);
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>4 使用AJAX同步编程,不能在状态码为2的时候获取到响应头的信息,可是状态码为4的时候也是能够获取到头和主体信息
}
xhr.send(null);
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json', false);
xhr.send(null);//=>执行后,只有状态码为4才会继续处理下面的代码
//=>状态码为4的时候绑定的,而状态不会在变了,因此方法不会执行
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
}
复制代码
/* * $.ajax() 基于原生JS的AJAX四步操做进行封装 * $.ajax([URL],[OPTIONS]) * $.ajax([OPTIONS]) URL在配置项中(推荐) * $.get/post/getJSON/getScript() * ...... * 配置项信息 * 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:回调函数,数据请求失败执行,方法中的参数是错误信息 */
$.ajax({
url: 'http://yapi.demo.qunar.com/mock/95100/project/list',
method: 'POST',
data: {
name: 'lanlan',
lx: 'teacher'
},
dataType: 'json',
async: true,
cache: false,
headers: {},
success: (result, status, xhr) => {
//=>xhr:是JQ帮咱们处理过的AJAX实例
console.log(result, status, xhr);
}
});
复制代码
<div id="box"></div>
<script>
//new Date()获取客户端本地当前时间(不能拿它作重要依据,由于用户能够随意修改)
/* * 倒计时抢购须要从服务器获取当前时间 AJAX * 问题:时间差(从服务器把时间给客户端,到客户端获取到这个信息,中间经历的时间就是时间差,而时间差是不可避免的,咱们应尽量减小这个偏差) * - 从响应头获取时间(AJAX异步) * - 基于HEAD请求(只获取响应头信息) */
let target = new Date('2019/09/14 13:27:00'),
now = null,
timer = null;
//=>从服务器获取时间:获取到时间后再作其余的事情
function func(callback) {
let xhr = new XMLHttpRequest;
xhr.open('HEAD', 'json/data.json', true);
xhr.onreadystatechange = function () {
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 2) { //从响应头中拿到时间
now = new Date(xhr.getResponseHeader('Date'));
callback && callback();
}
}
xhr.send(null);
}
//=>开启倒计时模式
function computed() {
let spanTime = target - now;
if (spanTime <= 0) {
//=>到抢购时间:结束定时器
clearInterval(timer);
timer = null;
box.innerHTML = "开抢~~";
return;
}
let hours = Math.floor(spanTime / (60 * 60 * 1000));
spanTime -= hours * 60 * 60 * 1000;
let minutes = Math.floor(spanTime / (60 * 1000));
spanTime -= minutes * 60 * 1000;
let seconds = Math.floor(spanTime / 1000);
box.innerHTML =
`距离抢购还剩 ${hours<10?'0'+hours:hours}:${minutes<10?'0'+minutes:minutes}:${seconds<10?'0'+seconds:seconds}`;
//=>每一次计算完,咱们须要让NOW在原来的基础上加上一秒(第一次从服务器获取到时间,后期直接基于这个时间本身加便可,不要每隔一秒从新从服务器拿)
now = new Date(now.getTime() + 1000);
}
func(() => {
//=>已经从服务器获取时间了
computed();
timer = setInterval(computed, 1000);
});
</script>
复制代码