【JavaScript】从入门到深刻了解AJAX

写在前面

AJAX做为前端中的核心部分,咱们可能在工做中,只是搬瓦工的角色,因此只会在写业务的时候给后端发送一个axiosfetch等请求,拿到数据渲染到页面后就无论不顾了,可是做为一个不想只是搬砖的工程师,深刻的了解它仍是很是有必要的,这篇文章将带你深刻了解AJAXjavascript

关于ajax的基础知识

ajax: 即async javascript and xml,就是异步的js和xmlhtml

关于XML

最先的时候,基于ajax从服务器获取的数据通常都是xml格式数据,只不过如今基本都是应用更小巧更方便操做的json格式处理前端

  • html超文本标记语言
  • xhtml严谨的html
  • xml可拓展的标记语言(基于标签结构存储数据)

异步js

基于ajax实现局部刷新java

  • 服务器渲染 通常都是同步 全局刷新ios

  • 客户端渲染 通常是异步 局部刷新git

基础操做

对于ajax的操做有核心的四步操做:github

建立xhr对象

let xhr = new XMLHttpRequest;
// 不兼容XMLHttpRequest的浏览器用ActiveXObject
let xhr = new ActiveXObject
复制代码

打开请求链接(配置请求信息)

xhr.open(method, url, async, user-name, user-pass),其中methodhttp请求的方法 不论是哪种请求方式,客户端均可以把信息传递给服务器,服务器也能够把信息返回给客户端,只不过get偏向于拿(给的少拿得多)web

  • get:从服务器获取ajax

    get请求url有长度限制:具体表现为ie: 2083字符,大约为2kb,谷歌: 8182字符大约为4kbjson

    • get/head(只获取响应头信息,不获取响应主题内容)

    • delete删除,通常代指删除服务器上指定的文件

    • options 试探性请求

      在cross跨域请求中,因此正常请求发送前,先发送一个试探请求,验证是否能够和服务器正常的创建链接

  • post:向服务器发送

    post偏向于给(给的多拿的少),post请求理论上没有大小限制

    • post/put新增,通常代指向服务器中新增文件
  • get请求和post的区别

    • get请求相对于post来讲,不安全,get请求传参是基于URL问号传参,会被别人基于URL劫持的方式把信息获取到有一句话说得好:“互联网面前人人都在裸奔”,因此没有绝对的安全,咱们须要更多的去处理安全性。

    • get请求容易产生缓存,缘由仍是由于get是基于问号传参传递信息的。浏览器在每一次获取数据后,通常会缓存一下数据,下一次若是请求的地址和参数和上一次同样,浏览器会直接获取缓存中的数据,因此咱们基于get发送请求,须要清除缓存的时候,通常都会在地址栏中添加一个随机数,相似于这样:_ = Math.random

  • 基于get向服务器发送请求,传递给服务器的方式:

    • 基于请求头传递给服务器(本地cookie信息传递给服务器)
    • 请求url地址后面的问号传参 === 主要方式
    • 监听请求状态,在不一样状态中作不一样的事情
    • 发送AJAX请求 ajax任务开始 直到响应主体信息返回
  • 基于post向服务器发送请求,传递给服务器的方式

传递给服务器的数据格式为application/x-www--form-urlencoded xx=xxx&xx=xxxxmultipart/form-data(表单提交、文件上传)、raw(能够上传textjsonxml等格式的文本)、binary(上传二进制数据或者编码格式的数据)

let xhr = new XMLHttpRequest
复制代码
  • ajax状态码
0 1 2 3 4
UNSENT OPENED HEADERS_RECEIVED LOADING DONE
建立完 完成open操做 响应头信息回来 响应主体信息正在返回中 响应主体已经返回
  • HTTP状态码

这里只列举常见状态码

200: OK,请求成功。通常用于GET与POST请求

304: Not Modified,未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端一般会缓存访问过的资源,经过提供一个头信息指出客户端但愿只返回在指定日期以后修改的资源

400: Bad Request,客户端请求的语法错误,服务器没法理解

401: Unauthorized,请求要求用户的身份认证

403: Forbidden,服务器理解请求客户端的请求,可是拒绝执行此请求

404: Not Found,服务器没法根据客户端的请求找到资源(网页)。经过此代码,网站设计人员可设置"您所请求的资源没法找到"的个性页面

500: Internal Server Error,服务器内部错误,没法完成请求

502: Bad Gateway,做为网关或者代理工做的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应

503: Service Unavailable,因为超载或系统维护,服务器暂时的没法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中

504: Gateway Time-out,充当网关或代理的服务器,未及时从远端服务器获取请求

注意:在真实项目中,后台开发者可能不是按照这个规则来处理的,无论传参或者权限是否正确等,只要服务器接收到请求最后都给返回200,在返回的json数据,基于某个字段表示错误信息。因此咱们要和后端沟通好~

  • xhr的一些方法
status = xhr.status;  // http状态码

state = xhr.readyState;

if(/^(2|3)\d{2}$/.test(status))  // 成功

xhr.getAllResponseHeaders()  响应头信息

xhr.getAllResponse("date")  服务器日期是格林尼治时间GMT  比北京时间晚了八小时  new Date处理

xhr.response         // 响应主体信息

xhr.setheaders

xhr.timeout

xhr.withCredentials   // 容许携带跨域

xhr.abort()  打断请求

// 请求头信息不能是中文和特殊字符,要编码
复制代码

ajax几种状态的同异步问题

let xhr = new XMLHttpRequest;
 /**
  *  xhr.readyState
  *  UNSENT 0 建立完默认为0
  *  OPENED 1 已经完成open操做
  *  HEADERS_RECEIVED 2 服务器已经把响应头信息返回了
  *  LOADING 3 响应主体正在返回中
  *  DONE 4 响应主体已经返回、
  *  xhr.open第三个参数控制的同步异步指的是从当前send发送请求开始,算任务开始,一直到状态为4才算任务结束,同步:在此期间 全部的事件都不去处理,
  *  而异步是:在此期间,该干啥干啥。
  *  异步 在SEND后会把这个请求的任务放在EVENT QUEUE中,属于宏任务
  */
// let xhr = new XMLHttpRequest;
// xhr.open("get", "./2.js", true);  // true为异步 false为同步
// // console.log(xhr.readyState);   // 1
// xhr.onreadystatechange = function() {
//     // 坚挺到状态改变后才会触发的事件
//     console.log(xhr.readyState);    // 2,3,4
    
// } 
// xhr.send();   // 任务开始

// let xhr = new XMLHttpRequest;
// xhr.open("get", "./2.js", true);  // true为异步 false为同步
// xhr.send();   // 任务开始
 // 此时状态是1
// xhr.onreadystatechange = function() {
//     // 坚挺到状态改变后才会触发的事件
//     console.log(xhr.readyState);    // 2,3,4
    
// } 

// let xhr = new XMLHttpRequest;
// xhr.open("get", "./2.js", false);  // true为异步 false为同步   同步特色 任务状态 不为4啥也干不了
// xhr.send();   // 任务开始

// // 状态为4,当下面变为5时才会改变, 因此没输出

// xhr.onreadystatechange = function() {   
//     console.log(xhr.readyState);      // 没有输出
// } 

// let xhr = new XMLHttpRequest;
// xhr.open("get", "./2.js", false);  // true为异步 false为同步   同步特色 任务状态 不为4啥也干不了

// // 这里状态为1, 
// xhr.onreadystatechange = function() {     // 这也是异步 的
//     console.log(xhr.readyState);      // 4
// } 

// xhr.send();   // 同步任务开始 状态不为4 啥也干不了  任务为4的时候,主栈才结束

let xhr = new XMLHttpRequest;
xhr.open("get", "./2.js", false);  // true为异步 false为同步   同步特色 任务状态 不为4啥也干不了

// 这里状态为1, 
xhr.onreadystatechange = function() {     // 这也是异步 的
    console.log(xhr.readyState);      // 4
} 

xhr.send();   // 同步任务开始 状态不为4 啥也干不了  任务为4的时候,主栈才结束
复制代码

实现倒计时功能

其实倒计时功能对于前端开发而言,是很简单的事情,可是在这简单的事情中,咱们还要注意些什么呢?

假如咱们如今想要实现一个倒计时抢购功能,咱们可能第一下想到的就是获取本地时间,计算与目标时间的时间差,试想一下,这样作会存在哪些问题?

你们都据说过这样一句话:“不要相信前端传送的任何数据”。是这样的,前端全部的数据都是可修改的,那么倒计时也是同理,若是我修改了系统时间岂不是就能够提早抢购了🐶

因此为了不这种状况的发生,咱们须要在真实项目中获取服务器的时间~

对于这件事情,我问过相关同事的处理方案,他们团队是经过接口获取的开始时间与结束时间,当开始时才显示,不开始时不显示任何倒计时,固然这个是和需求有关系的,若是想在开始前显示倒计时,那么获取服务器当前时间是必不可少的~

那么获取服务器的时间,又会存在什么样的问题呢?

咱们要基于ajax请求获取响应头中的信息,那么在客户端和服务端通讯的过程当中,势必存在时间的消耗,那么到达本地的时间就会存在必定的偏差,这个偏差是根据网络环境等因素影响的,差值也并非固定的,因此它是必定存在的,咱们在开发过程当中,也只能是尽量的去减小这个偏差~

假如咱们抢购的目标时间是2020.6.10 20:00【这个模块是在6月10号这一天写的,哈哈哈】,下面咱们完成这个倒计时抢购功能

  • 首先在页面中要有一个显示倒计时时间的区域
<div>
    距离抢购时间还剩:
    <span id="spanBox"></span>
</div>
复制代码
  • 封装获取服务器时间函数
function queryServerTime() {
    return new Promise(resolve => {
        let xhr = new XMLHttpRequest;
        xhr.open("head", './data.json');
        xhr.onreadystatechange = function() {
            if(!/^(2|3)\d{2}$/.test(xhr.status)) return;
            if(xhr.readyState === 2) {  // 响应头信息返回时,即获取
                // 响应头信息已经返回
                let time = xhr.getResponseHeader("date");
                time = new Date(time);
                resolve(time)
            }
        }
        xhr.send();
    })
}
复制代码
  • 业务函数
async function init() {
    let serverTime = await queryServerTime(),
        targetTime = new Date('2020/06/10 20:00:00'),
        autoTimer = null;

    // 计算时间差
    function computed() {
        let spanTime = targetTime - serverTime;
        if(spanTime <= 0) {
            spanBox.innerHTML = `00:00:00`;
            clearInterval(autoTimer);
        }
        let hours = Math.floor(spanTime/(60*60*1000));
        spanTime = spanTime - hours*60*60*1000;
        let minutes = Math.floor(spanTime/(60*1000))
        spanTime = spanTime -minutes*60*1000;
        let seconds = Math.floor(spanTime / 1000)

        hours = hours < 10 ? "0" + hours : hours;
        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;
        spanBox.innerHTML = `${hours}:${minutes}:${seconds}`;
    }
    computed();

    // 1s计算一次
    autoTimer = setInterval(_ => {
        // 从新获取服务器时间  可是这样有很大延迟 、服务器压力也大
        // 咱们能够基于第一次获取的时间,在原来的基础上,让其自动累加
        serverTime = new Date(serverTime.getTime() + 1000)
        computed()
    }, 1000)
}

init();
复制代码

这样,倒计时的功能就基于ajax实现了,完整的代码在这里

封装一个本身的ajax

说到封装,个人第一篇掘金博客就是封装一个本身的ajax,不过那个有些过于“单薄”,连接在这里:封装ajax请求的两种方式

对于封装的过程本篇文章不详细列举~封装好的、更完善一些的ajax在这里,各位小伙伴移步这里获取哦~

最后

本篇文章从说ajax的基础一路到封装,若是文章有不对之处还请你们指出,咱们共同窗习~共同进步~

最后,推荐一下个人公众号「web前端日记」,欢迎小伙伴前来关注哦~

相关文章
相关标签/搜索