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条新闻。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容