AJAX

浏览器与服务器之间,采用HTTP协议通信。用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出HTTP请求。

1999年,微软公司发布IE浏览器5.0版,第一次引入新功能:允许JavaScript脚本向服务器发起HTTP请求。这个功能当时并没有引起注意,直到2004年Gmail发布和2005年Google Map发布,才引起广泛重视。2005年2月,AJAX这个词第一次正式提出,指围绕这个功能进行开发的一整套做法。从此,AJAX成为脚本发起HTTP通信的代名词,W3C也在2006年发布了它的国际标准。

具体来说,AJAX包括以下几个步骤。

  1. 创建AJAX对象
  2. 发出HTTP请求
  3. 接收服务器传回的数据
  4. 更新网页数据

概括起来,就是一句话,AJAX通过原生的XMLHttpRequest对象发出HTTP请求,得到服务器返回的数据后,再进行处理。

AJAX可以是同步请求,也可以是异步请求。但是,大多数情况下,特指异步请求。因为同步的Ajax请求,对浏览器有“堵塞效应”。

注意,AJAX只能向同源网址(协议、域名、端口都相同)发出HTTP请求,如果发出跨源请求,就会报错。

1、AJAX 是什么?有什么作用?

  1. AJAX:是对Asynchronous JavaScript and XML的简写,是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。这一技术能够向服务器请求额外的数据而无需从新加载页面。
  2. 作用:传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。而通过使用ajax可以在后台与服务器进行少量数据交换, 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

2、Ajax和XMLHttpRequest

Ajax核心的技术是XMLHttpRequest对象(简称XHR)。我们通常将Ajax等同于XMLHttpRequest,但细究起来它们两个是属于不同维度的2个概念。

Ajax:(摘自what is Ajax)AJAX stands for Asynchronous JavaScript and XML. AJAX is a new technique for creating better, faster, and more interactive web applications with the help of XML, HTML, CSS, and Java Script. AJAX is based on the following open standards:

  • Browser-based presentation using HTML and Cascading Style Sheets (CSS).
  • Data is stored in XML format and fetched from the server.
  • Behind-the-scenes data fetches using XMLHttpRequest objects in the browser.
  • JavaScript to make everything happen.

从上面的解释中可以知道:Ajax是一种技术方案,但并不是一种新技术。它依赖的是现有的CSS/HTML/Javascript,而其中最核心的依赖是浏览器提供的 XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。

所以用一句话来总结两者的关系,就是:我们使用XMLHttpRequest对象来发送一个Ajax请求。

3、XMLHttpRequest对象

1、什么是XMLHttpRequest?

  • XMLHttpRequest是原生JS的一个内置对象,用来在浏览器与服务器之间传送数据,一旦拿到服务器返回的数据,AJAX不会刷新整个网页,而是只更新相关部分,从而不打断用户正在做的事情。XMLHttpRequestAJAX技术的核心,学习AJAX实质上就是在学习XMLHttpRequest

2、如何创建XMLHttpRequest对象:

  • 一般使用new关键字进行创建,然后赋值给一个变量,如下:
var xhr = new XMLHttpRequest();

4、XMLHttpRequest对象的常用属性

1、readyState

只读属性,表示XMLHttpRequest请求当前所处的状态,共有五个数字值(0,1,2,3,4,5)。

  • 0:表示XMLHttpRequest实例已经生成,但是open()方法还没有被调用。
  • 1:表示已调用open方法,但还未调用send方法(请求还未被发送出去),仍然可以使用setRequestHeader(),设定HTTP请求的头信息。
  • 2:表示send方法已调用,数据已发送,并且服务器接收到了请求。
  • 3:表示服务器正在传输数据。
  • 4:表示数据传输完成。

在通信过程中,每当发生状态变化的时候,readyState属性的值就会发生改变。这个值每一次变化,都会触发readyStateChange事件。

2、status

只读属性,表示本次请求所得到的HTTP状态码,返回一个整数。一般来说,如果通信成功的话,这个状态码是200。常用的有如下几个状态码:

  • 200:OK(正常访问);
  • 301:Moved Permanently(永久移动);
  • 302:Moved temporarily(暂时移动);
  • 304:Not Modified(未修改);
  • 307:Temporary Redirect(暂时重定向);
  • 401:Unauthorized (未授权);
  • 403:Forbidden(禁止访问);
  • 404:Not Found(未找到该网址);
  • 500:Internal Server Error (找到网址但服务器发生错误);

基本上,只有200和304的状态码,表示服务器返回是正常状态。|

3、 statusText

与status属性类似,返回本次请求的状态,不同点在于,status只返回一个数字,而该属性返回一个字符串 ,包含整个状态信息,比如”200 OK“|

4、responseType

responseType属性用来指定服务器返回数据(xhr.response)的类型。可通过对该属性赋值来指定接收的数据类型,默认为字符串,有如下几种数据类型:

  • text:以字符串形式接收数据;
  • json:以json对象形式接收数据;
  • blob:blob对象;
  • ArrayBuffer:ArrayBuffer对象;

5、response、responseText、responseXML

三者都是服务器返回的数据,如果数据不完整或者获取失败,它们的值就为null。

不同点:

  • response返回的是数据的主体部分,可以为任何类型(数组,json,XML,字符串等);
  • responseText返回从服务器接收到的字符串。该属性为只读。如果本次请求没有成功或者数据不完整,该属性就会等于null。如果服务器返回的数据格式是JSON,就可以使用responseText属性;
//返回JSON格式的字符串
var data = ajax.responseText;
//把JSON格式的字符串转换为JavaScript对象
data = JSON.parse(data);
  • responseXML返回从服务器接收到的Document对象,该属性为只读。如果本次请求没有成功,或者数据不完整,或者不能被解析为XML或HTML,该属性等于null。该值返回的数据会被直接解析DOM;

5、XMLHttpRequest对象的常用方法

1、abort()

abort方法用来终止已经发出的HTTP请求。

2、getAllResponseHeaders()

getAllResponseHeaders方法返回服务器发来的所有HTTP头信息。格式为字符串,每个头信息之间使用CRLF分隔,如果没有受到服务器回应,该属性返回null,该方法不需要接受参数。

3、getResponseHeader()

getResponseHeader方法返回HTTP头信息指定字段的值,如果还没有收到服务器回应或者指定字段不存在,则该属性为null。该方法需要接受一个参数,用来返回指定字段的值。

4、open()

XMLHttpRequest对象的open方法用于指定发送HTTP请求的参数,常用的有三个参数:

  • 第一个参数:请求的类型(常用get或者post);
  • 第二个参数是接口名和:这里要分两种情况:
  • get请求时:接口名+请求参数(键值对形式);post请求时:只需要接口名(需要传递的参数写在send方法里);
  • 第三个参数:一个布尔值,指定是否异步(true为异步,false为同步,通常为true,默认为true);

第四和第五个参数:填写用于认证的用户名和密码;

5、send()

send方法用于实际发出HTTP请求。如果不带参数,就表示HTTP请求只包含头信息,也就是只有一个URL,典型例子就是GET请求;如果带有参数,就表示除了头信息,还带有包含具体数据的信息体,典型例子就是POST请求。

如果是POST请求还要在open()之后、send()之前使setRequestHeader方法设置HTTP头信息。

ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

6、setRequestHeader()

setRequestHeader方法用于设置HTTP头信息。该方法必须在open()之后、send()之前调用。

6、XMLHttpRequest对象的事件以及对应的事件监听接口

image.png

7、 前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?

mock数据指的是在后端开发没有完成时,前端可以通过mock方法搭建本地服务器,模拟后台数据来实现数据交互的效果

前后端开发联调需要注意哪些事情:

  1. 约定数据:有哪些需要传输的数据,数据类型是什么。
  2. 约定接口:确定接口名称以及请求和响应的方法(get or post),请求的参数名称,响应的数据格式。
  3. 根据这些约定整理成接口文档。

后端接口完成前如何 mock 数据:

  1. 根据接口文档,使用假数据来验证制作的网页响应和接口是否正常。
  2. 可以使用server-mock。

3,可以搭建php本地服务器用,php写脚本提供临时数据。

8、点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?

利用布尔值设置一个状态锁,在触发ajax前和数据到来的时候布尔值设置为true,是不锁定的;发送数据之后布尔值为false,是锁定的。若重复点击在数据没有到来之前也就是布尔值为true时,会把重复点击忽略。

//利用布尔值作为状态锁
var lock = true; 
btn.addEventListener('click',function(){
   //用户重复点击,数据没有到来之前直接return,忽略重复点击
   if(!lock ){
     return;
   }
   ajax({
     ...
     //数据到来,布尔值设为true
     lock = true; 
   })
   xhr.open(...,...,...);
   xhr.send();
   //发送ajax请求,这时数据还没有到来,布尔值设为false
   lock = false; 
});

9、封装AJAX实现加载更多

这里使用server-mock来mock数据。server-mock是一款nodejs命令行工具,用于搭建web服务器,模拟网站后端,方便前端开发者Mock数据。

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <style>
    ul,li{
      margin; 0;
      padding: 0
    }
    #ct li{
      list-style: none;
      border:1px solid #ccc;
      padding:10px;
      margin-top: 10px;
      cursor:pointer;
    }
    #load-more{
      display: block;
      margin:10px auto;
      text-align: center;
      cursor: pointer;
    }
    .btn{
      display: inline-block;;
      height: 40px;
      line-height: 40px;
      width: 80px;
      border: 1px solid #E27272;
      border-radius: 3px;
      text-align: center;
      text-decoration: none;
      color:#E27272;
    }
    .btn:hover{
      background: green;
      color:#fff;
    }
  </style>
</head>
<body>
  <ul id="ct">   
  </ul>
  <a id="load-more" class="btn" href="#">
    加载更多
  </a>
  <script>
    var btn = document.querySelector('#load-more');
    var ct = document.querySelector('#ct');
    var pageIndex = 0;
    //设置状态锁,防止数据到来之前用户重复点击
    var isDataArrive = true;

    btn.addEventListener('click',function (e) {
       e.preventDefault();
       
       if (!isDataArrive) {
       return;
       }

       loadData(function(news){
        renderPage(news);     
       })     
    })

    function loadData(callback){
      ajax({
        type: 'get',
        url: '/loadMore',
        data: {
          index: pageIndex,
          length: 5
        },
        onSuccess: callback,
        onError: function(){
          console.log('出错了')
        }
      })
    }

    function renderPage(results){
       var fragment = document.createDocumentFragment();
            for (var i = 0; i < results.length; i++) {
              var node = document.createElement('li');
              node.innerText = results[i];
              fragment.appendChild(node);
            }
            ct.appendChild(fragment)           
    }

    function ajax(options){
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function(){
        if (xhr.readyState === 4) {
          if (xhr.status === 200 || xhr.status === 304) {
            //与后端约定好,传输的数据类型为JSON字符串,JSON.parse()用来把JSON字符串解析为原生JavaScript值
            var results = JSON.parse(xhr.responseText);
            options.onSuccess(results);
            pageIndex = pageIndex + 5;
          }else{
            options.onError();
          }
          //数据到来,布尔值设为true
          isDataArrive = true
        }
      }

      var str = '';
      for(var key in options.data){
        str +=  key + '=' + options.data[key] + '&';   
      }
      str = str.substr(0, str.length-1);

      if(options.type.toLowerCase() === 'get'){
        xhr.open(options.type, options.url + '?' + str, true)
        xhr.send()
      }
      if(options.type.toLowerCase() === 'post'){
        xhr.open('post', options.url, true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(str);
      }
      //发送ajax请求,这时数据还没有到来,布尔值设为false
      isDataArrive = false;
    }
   
  </script>
</body>
</html>

router.js

app.get('/loadMore',function(req,res){

  var curIdx = req.query.index;
  var len= req.query.length;
  var data = [];

  for (var i = 0; i < len; i++) {
    data.push('新闻' + (parseInt(curIdx) + i))
  }

  res.send(data);
})


app.post('/loadMore',function(req,res){

  var curIdx = req.body.index;
  var len= req.body.length;
  var data = [];

  for (var i = 0; i < len; i++) {
    data.push('新闻' + (parseInt(curIdx) + i))
  }

  res.send(data);
})

image.png

image.png

image.png

每次点击加载更多按钮都会发送一条AJAX请求,数据没回来之前,重复点击会被忽略,数据到来后会渲染到页面上出现5条新闻。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青青天空树

postMessage 消息传递

        web开发了,除了前台与服务器交换数据,还有可能前台页面间需要进行数据传递,比如窗口间,页面和嵌套的iframe间。这些问题之前都有解决办法,但...

783
来自专栏C/C++基础

Protocol Buffers C++入门教程

protobuf(Protocol Buffers )是Google的开源项目,是Google的中立于语言、平台,可扩展的用于序列化结构化数据的解决方案。官网见...

1531
来自专栏架构之路

深入探讨 Java 类加载器

看到一篇写得非常好的加载器文章,转过来与大家分享一下(https://www.ibm.com/developerworks/cn/java/j-lo-class...

3214
来自专栏开源优测

JMeter处理器09

前言 在jmeter中提供了两种处理器,用于修改请求数据或处理响应数据。 ? 前置处理器 后置处理器 前置处理器 前置处理器是在请求发送前做相关处理。可以用于在...

2894
来自专栏前端技术总结

这次,我们聊聊ajax的创建过程

ajax:一种客户端向服务器请求数据的方式,不需要去刷新整个页面; ajax的核心:XMLHttpRequest对象

1.5K68
来自专栏破晓之歌

vue中axios处理http发送请求的示例(Post和get)

axios中文文档:https://github.com/mzabriskie/axios#using-applicationx-www-form-urlenc...

633
来自专栏前端知识分享

第207天:HTTP协议头字段详解大全

HTTP Header非常之多,很少有人能完全分清这些Header到底是干什么的。鉴于RFC文件规范艰深晦涩难懂,本文对协议规范中列出的HTTP Header进...

973
来自专栏超然的博客

前端基础精简总结

ES5: String、Number、Boolean、Null、Undefined、Object ES6增: Symbol 其中,object为引用,其...

843
来自专栏晓晨的专栏

ASP.NET Core 中间件(Middleware)详解

1052
来自专栏Python中文社区

PyQt的一个UI单元测试框架思路

專 欄 ❈丁果,Python中文社区作者。对django、pyqt、opencv、tornado感兴趣。 GitHub:https://github.com/...

2406

扫码关注云+社区