Ajax总结

目录(?)[+]

Ajax全称Asynchronous JavaScript and XML,也就是异步的js和XML技术。现在网页中Ajax几乎无所不在,前后端的分离也离不开Ajax的异步通信技术。

浏览器为Ajax做了些什么?

现在的浏览器当中,虽然几乎都支持了Ajax,但他们的技术方案都分为两种: 
1,标准浏览器是通过XMLHttpRequest对象来实现Ajax的功能。

var xhr = new XMLHttpRequest();

2,IE浏览器是通过XMLHttpRequest或者ActiveXObjet对象来实现Ajax的功能。 
但是由于IE版本众多,实现的方法也不尽相同。如果想要采取全兼容方案的话:

function getXHR(){
  var xhr = null;
  if(window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
    try {
      xhr = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) { 
        alert("您的浏览器暂不支持Ajax!");
      }
    }
  }
  return xhr;
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Ajax有没有破坏js单线程机制

对于这个问题,我们可以需要知道浏览器的线程:

  • GUI渲染线程
  • JavaScript引擎线程
  • 浏览器事件触发线程
  • HTTP请求线程

    那么这些线程,又是怎么和js引擎线程进行交互呢? 
    通常来说,线程间的交互是以事件的方式来发生的,通过事件回调的方式予以通知其他线程。但是事件回调,又是以先进先出的队列方式添加到任务队列的末尾,等到js引擎空闲的时候,任务队列中排队的任务就会依次被执行。 
    浏览器中,js引擎线程会循环从任务队列中读取事件并且执行,这种运行机制成为Event Loop(事件循环)。 
    对于一个Ajax请求,js引擎会首先生成XMLHttpRequest实例对象,然后完成open方法,调用send方法。到这里,所有的语句还是同步执行的。但是从send方法内部开始,浏览器要为将要发生的网络请求创建新的http请求线程,这个线程独立于js引擎线程,于是乎网络请求被异步发送出去了。但是另一方面,js引擎并不会等待Ajax发起的Http请求的Response,而是按顺序依次往下执行。 
    当Ajax请求被服务器响应并且User Agent收到response后,浏览器事件触发线程就会捕获到Ajax的回调事件onreadystatechange(当然也可能触发onload或者onerror事件)。该回调事件并没有被立即执行,而是被添加到了任务队列的末尾。直到js引擎空闲了,任务队列的任务才被捞出来,按照添加的顺序,挨个执行,当然也包括刚刚append到队列末尾的onreadystatechange事件。 
    在onreadystatechange事件内部,有可能对DOM进行操作,此时浏览器便会挂起js引擎线程,转而执行GUI渲染线程,进而UI重绘(repaint)或者回流(reflow)。当js引擎重新执行时,GUI渲染线程又会被挂起,GUI更新将被保存起来,等到js引擎空闲时立即被执行。 
    以上整个Ajax请求过程中,有涉及到浏览器的4种线程,其中除了GUI渲染线程js引擎线程是互斥的。其他线程相互之间都是可以并行执行的。通过这样的一种方式,Ajax并没有破坏js的单线程机制。

Ajax与setTimeout排队问题

通常来说,Ajax和setTimeout的事件回调都被同等的对待,那么就会按照顺序自动地被添加到任务队列的末尾,等待js引擎空闲的时候,但请注意,并非xhr的所有回调执行都滞后于setTimeout的回调。

function ajax(url, method){
  var xhr = getXHR();
  xhr.onreadystatechange = function(){
    console.log('xhr.readyState:' + this.readyState);
  }
  xhr.onloadstart = function(){
    console.log('onloadStart');
  }
  xhr.onload = function(){
    console.log('onload');
  }
  xhr.open(method, url, true);
  xhr.setRequestHeader('Cache-Control',3600);
  xhr.send();
}
var timer = setTimeout(function(){
  console.log('setTimeout');
},0);
ajax('http://louiszhai.github.io/docImages/ajax01.png','GET');

   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

Ajax总结_第1张图片 
由于Ajax异步,所以setTimeout回调本应该最先被执行,然后实际上,一次ajax请求,并非所有的部分都是异步的。至少在readyState == 1 的onreadystatechange回调以及onloadstart回调就是同步执行的,因此它们的输出排在最前面。

XMLHttpRequest属性解读

首先在chrome console下创建一个XMLHttpRequest实例对象xhr,如下所示: 
Ajax总结_第2张图片 
运行以下代码:

var xhr = new XMLHttpRequest(),
    i=0;
for(var key in xhr){
    if(xhr.hasOwnProperty(key)){
       i++;
   }
}
console.log(i);//0
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

就会发现XMLHttpRequest实例对象其实并没有一个自有属性!这是因为它是BOM对象(Browser Object Model)

通常来说,一个xhr实例对象拥有10个普通属性和9个方法。

readyState 
只读属性,readyState属性记录了ajax调用过程中所有可能的状态,它的取值简单明了,如下:

Ajax总结_第3张图片

注意,readyState是一个只读属性,想要改变它的值是不可行的。

onreadystatechange


onreadystatechange事件回调方法是在readystate状态发生改变的时候触发的,在一个收到响应的ajax请求周期中,onreadystatechange方法会被触发4次。因此可以在onreadystatechange方法中绑定一些事件回调,比如:

xhr.onreadystatechange = function(e){
  if(xhr.readystate==4){
    var s = xhr.status;
    if((s >= 200 && s < 300) || s == 304){
      var resp = xhr.responseText;
      //TODO ...
    }
  }
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意: onreadystatechange回调中默认会传入Event实例,如下: 
Ajax总结_第4张图片

status


只读属性,status表示http请求的状态,初始值为0。就是状态码。

statusText


只读属性,statusText表示服务器的响应状态信息,它是一个UTF-16的字符串,请求成功且status == 20X时,返回的大写OK。请求失败的返回空字符串。其他情况下返回响应的状态描述。

onloadstart


onloadstart事件回调方法在ajax请求发送之前触发,触发的时机是在readyState == 1状态之后,readyState == 2 状态之前。也就是在open()方法调用之后,send()方法调用之前。

onprogress


onprogress事件回调方法在readystate==3状态时触发,默认传入了ProgressEvent对象,可以通过e.loaded/e.total 来计算加载资源的进度,该方法用于获取资源的下载进度。 
注意:该方法适用于IE10+及其他现代浏览器。

xhr.onprogress = function(e){
    console.log('progress:',e.loaded/e.total);
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

onload


onload事件回调方法在ajax请求成功后触发,触发时机在readyState == 4 状态孩子后,所以说要想捕捉到一个ajax异步请求的成功状态,并且执行回调,一般下面的语句就足够了:

xhr.onload = function(){
    var s = xhr.status;
    if((s >= 200 && s < 300) || s == 304){
        var resp = xhr.responseText;
    }
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

onload


onloadend 事件回调方法在ajax请求完成时触发,触发时机在readyState == 4 状态之后(收到响应时)或者readyState ==2状态之后(未收到响应时)。 
注意:onloadend方法也会默认传入一个ProgressEvent事件进度对象。

timeout


timeout属性用于指定ajax的超时时长,通过它可以灵活地控制ajax的请求时间上限。timeout的值满足如下规则:

xhr.timeout = 0; //不生效
xhr.timeout = '123'; //生效, 值为123
xhr.timeout = '123s'; //不生效
xhr.timeout = ['123']; //生效, 值为123
xhr.timeout = {a:123}; //不生效
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

ontimeout


ontimeout方法在ajax请求超时时触发,通过它可以在ajax请求超时时做一些后续处理。

xhr.ontimeout = function(e){
    console.log('请求超时!!!')
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

response responseText


均为只读属性,response表示服务器的响应内容,相应的,responseText表示服务器响应内容的文本形式。

responseXML


只读属性,responseXML表示xml形式的响应数据,缺省为null。如果数据不是xml格式,就会报错。

responseType


responseType表示响应的类型,缺省的话为空字符串,其值可取的''arraybuffer''''blob'' ,''document''''json'',and ''text''共五种类型。

responseURL


reponseURL 返回 ajax 请求最终的URL。

withCredentials


withCredentials 是一个布尔值,默认为false,表示跨域请求中不发送cookie等信息。当它设置为true时,cookieauthorization headers 或者TLS客户端证书 都可以正常发送和接收,显然它的值对同域请求没有影响。 
注意: 该属性适用于IE10+, opera 12+ 及其他现代浏览器。

abort


abort方法用于取消ajax请求,取消后,readyState状态被设置为0(UNSENT)。如下,调用abort方法后,请求将被取消。

getResponseHeader


getResponseHeader 方法用于获取ajax 响应头中指定name 的值。 如果response header 中存在相同的name ,那么它们的值将自动以字符串的形式连接在一下。

console.log(xhr.getResponseHeader('Content-Type'));
   
   
     
     
     
     
  • 1
  • 1

getAllResponseHeaders


getAllRequestHeaders方法用于获取所有安全的ajax响应头,响应头以字符串形式返回。每个HTTP报头名称和值用冒号分隔,如key:value , 并以\r\n结束。

xhr.onreadystatechange = function(){
    if(this.readyState == this.HEADERS_RECEIVED){
        console.log(this.getAllResponseHeaders());
    }
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

setRequestHeader


既然可以获取响应头,那么自然也也可以设置请求头,setRequestHeader就是干这个的,如下:

//指定请求的type为json格式
xhr.setRequestHeader('Content-type','application/json');
//除此之外,还可以设置其他的请求头
xhr.setRequestHeader('x-requested-with','123456');
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

onerror


onerror 方法用于在ajax 请求出错后执行,通常只在网络出现问题时或者ERR_CONNECTION_RESET时触发(如果请求返回的是407状态码,chrome下也会触发onerror)

upload


upload 属性默认返回一个XMLHttpRequestUpload对象,用于上传资源,该对象具有如下方法:

  • onloadstart
  • onprogress
  • onabort
  • onerror
  • onload
  • ontimeout
  • onloadend 
    上述方法功能与xhr对象中同名方法一致。其中,onprogress事件回调方法可用于跟踪资源上传的进度。
xhr.upload.onprogress = function(e){
    var percent = 100 * e.loaded / e.total | 0;
    console.log('upload:' + percent + '%')
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

XHR一级

XHR1 即 XMLHttpRequest Level 1. XHR1时,xhr对象具有如下缺点:

  • 仅支持文本数据传输,无法传输二进制数据。
  • 传输数据时,没有进度信息提示,只能提示否否完成。
  • 受浏览器 同源策略 限制,只能请求同域资源。
  • 没有超时限制,不方便掌控ajax请求节奏。

XHR二级

XHR2 即XHMHttpRequest Level 2。XHR2针对XHR1 的上述缺点做了如下改进:

  • 支持二进制数据,可以上传文件,可以使用FormData对象管理表单。
  • 提供进度提示,可通过xhr.upload.onprogress事件回调获取传输进度。
  • 依然受 同源策略 限制,这个安全机制是不会改变的,但是XHR2 提供了 Access-Control-Allow-Origin等headers,设置为*时表示允许任何域名请求,从而实现跨域CORS 访问。
  • 可以设置timeout及ontimeout,方便设置超时时长和超时后续处理。

    这里就H5新增的FormData对象举个例子。

//可以直接创建FormData实例
var data = new FormData();
data.append('name','louis');
xhr.send(data);

//还可以通过传入表单DOM对象来创建FormData实例
var form = document.getElementById('form');
var data = new FormData('form');
data.append('password','123456');
xhr.send(data);
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

目前,主流浏览器都支持了XHR2,除了IE系列需要IE10及更高版本,因此IE10以下是不支持XHR2的。

而对于IE 8,9用户来说,可以使用一个阉割版的XDomainRequest可用,IE7则没有。

$.ajax


$.ajax 是jQuery对原生ajax的一次封装。通过封装ajax,jQuery抹平了不同版本浏览器异步http的差异性,取而代之的是高度统一的api。

Axios

实际上,如果你仅仅只是想要一个不错的http库,相比于庞大臃肿的jQuery,短小精悍的Axios可能更加适合你,原因如下:

  • Axios 支持node,jQuery并不支持。
  • Axios 基于promise语法,jq3.0才开始全面支持。
  • Axios 短小精悍,更加适合http常见,jquery大而全,加载慢。 
    Axios 大小仅为12k。 
    语法上Axios 基本就和promise一样,在then方法中处理回调,在catch方法中处理异常。如下:
axios.get('http://api.github.com/users/jiamianmao')
.then(function (response){
    console.log(response);
})
.catch(function (error){
    console.log(error);
})
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

除了get, 它还支持post, delete, head, put, patch, request请求

Fetch

说到ajax,就不得不提及fetch,可以点击:http://louiszhai.github.io/2016/11/02/fetch/

Ajax跨域请求

什么是CORS


CORS是一个W3C(World Wide Web 标准),全称是跨域资源共享(Cross-origin resource sharing)。它允许浏览器向跨域服务器,发出异步Http请求,从而克服了ajax受同源策略的限制。实际上,浏览器不会拦截不合法的跨域请求,而是拦截了他们的响应,因此即使请求不合法,很多时候,服务器依然接收到了请求(Chrome和Firefox 下https 网站不允许发送http异步请求除外) 
Ajax总结_第5张图片

移动端CORS兼容性


当前几乎所有的桌面浏览器(IE8+,Firefox 3.5+ ,Safari 4+ 和 Chrome 3+)都可以通过名为跨域资源共享的协议支持ajax跨域调用。

那么移动端兼容性又如何呢?请看下图: 
Ajax总结_第6张图片

可见,CORS的技术在iOS Safari 7.1 及 Android webview 2.3 中就早已支持。

CORS 有关的headers


1)HTTP Request Header (服务器提供):

  • Access-Control-Allow-Origin: 指定允许哪些源的网页发送请求。
  • Access-Control-Allow-Credentials:指定是否允许发送cookie。
  • Access-Control-Allow-Methods:指定允许哪些请求方法。
  • Access-Control-Allow-Headers:指定允许哪些常规的头域字段,比如说Content-Type。
  • Access-Control-Expose-Header:指定允许哪些额外的头域字段,比如说X-Custom-Header。 
    该字段可省略. CORS请求时, xhr.getResponseHeader() 方法默认只能获取6个基本字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma . 如果需要获取其他字段, 就需要在Access-Control-Expose-Headers 中指定. 如上, 这样xhr.getResponseHeader(‘X-Custom-Header’) 才能返回X-Custom-Header字段的值.(该部分摘自阮一峰老师博客) 
    Access-Control-Max-Age: 指定preflight OPTIONS请求的有效期, 单位为秒.

2)HTTP Request Header(浏览器OPTIONS请求默认自带):

  • Access-Control-Request-Method: 告知服务器,浏览器将发送哪种请求, 比如说POST.
  • Access-Control-Request-Headers: 告知服务器, 浏览器将包含哪些额外的头域字段.

3) 以下所有的header name 是被拒绝的: 
- Accept-Charset 
- Accept-Encoding 
- Access-Control-Request-Headers 
- Access-Control-Request-Method 
- Connection 
- Content-Length 
- Cookie 
- Cookie2 
- Date 
- DNT 
- Expect 
- Host 
- Keep-Alive 
- Origin 
- Referer 
- TE 
- Trailer 
- Transfer-Encoding 
- Upgrade 
- Via 
- 包含以Proxy- 或 Sec- 开头的header name

CORS请求


CORS请求分为两种,1,简单请求;2,非简单请求。 
满足如下两个条件的便是简单请求,反之则为非简单请求。 
1,请求是以下三种之一:

  • GET
  • POST
  • HEAD

2,http头域不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type 字段限制三个值 application/x-www-form-urlencoded ,multipart/form-data , text/plain

对于简单的请求,浏览器将发送一次http请求,同时在Request头域中增加Origin字段,用来标示请求发起的源,服务器根据这个源采取不同的响应策略,如服务器认为请求合法,那么需要往返会得HTTP Respinse 中添加 Access-Control-* 等字段。

对于非简单请求, 比如Method为POST且Content-Type值为 application/json 的请求或者Method为 PUT 或 DELETE 的请求, 浏览器将发送两次http请求. 第一次为preflight预检(Method: OPTIONS),主要验证来源是否合法. 值得注意的是:OPTION请求响应头同样需要包含 Access-Control-* 字段等. 第二次才是真正的HTTP请求. 所以服务器必须处理OPTIONS应答(通常需要返回20X的状态码, 否则xhr.onerror事件将被触发). 
以上请求流程图为: 
Ajax总结_第7张图片

HTML启用CORS


http-equiv相当于http的响应头,它回应给浏览器一写有用的信息,以确保正确和精确地显示网页内容。 
如下html将允许任意域名下的网页跨域访问。

http-equiv = 'Access-Control-Allow-Origin' content='*'>
   
   
     
     
     
     
  • 1
  • 1

图片启用CORS


通常,图片允许跨域访问,也可以在canvas中使用跨域的图片,但这样做会污染画布,一旦画布受污染,将无法读取其数据。

ajax文件上传

Ajax实现文件上传非常简单,这里我选取原生js,jq分别来比较下,并顺便聊聊使用它们时的注意事项。

1) 为了上传文件,我们得先选中一个文件,一个type为file 的input框就够了。

'input' type='file'>
   
   
     
     
     
     
  • 1
  • 1

2) 然后用FormData 对象包裹选中的文件。

var input = document.getElementById('input');
    formData = new FormData();
formData.append('file',input.files[0]);  //key可以随意定义,只要后台能理解就行
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

3) 定义上传的URL。

var url = 'http://loaclhost:10108/test',
    method = 'POST';
   
   
     
     
     
     
  • 1
  • 2
  • 1
  • 2

js文件上传


function ajax(url,method,data){
    var xhr = null;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else if(window.ActiveXObject){
        try{
            xhr = new ActiveXObject('Msxml2.XMLHTTP');
        }catch (e){
            try{
                xhr = new ActiveXObject('Microsoft.XMLHTTP');
            }catch (e){
                alert('您的浏览器不支持Ajax!')
            }
        }
    }
    xhr.onerror = function(e){
        console.log(e);
    }
    xhr.open(method,url);
    try{
        setTimeout(function (){
            xhr.send(data);
        });
    }catch (e){
        console.log('error:',e);
    }
    return xhr;
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

4.2 )上传文件并绑定事件.

var xhr = ajax(url,mthod,formData);
xhr.upload.onprogress = function(e){
    console.log('upload progress',e.loaded/e.total*100 + '%');
};
xhr.upload.onload = function (){
    console.log('upload onload');
}
xhr.onload = function(){
    console.log('onload');
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上传结果如下所示: 
Ajax总结_第8张图片

fetch 上传


5) fetch 上传只要发送一个post请求,并且body属性设置为formData即可。遗憾的是,fetch无法跟踪上传的进度信息。

fetch(url,{
    method:method,
    body:formData
}).then(function (res){
    console.log(res);
}).cathc(function(e){
    console.log(e);
});
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

jquery文件上传


jq提供了各式各样的上传插件,其原理都是利用jq自身的ajax方法。 
6) jq的ajax提供了xhr属性用于自定义各种事件

$.ajax({
    type:method,
    url:url,
    data:formData,
    processData:false,
    contentType:false,  //必须为false才会自动加上正确的Content-Type
    xhr:function(){
        var xhr = $.ajaxSettings.xhr();//实际上就是return new window.XMLHttpRequest()对象
        if(xhr.upload){
            xhr.upload.addEventListener('progress',function(e){
                console.log('jq upload progress:',e.loaded/e.total * 100 + '%');
            },false);
            xhr.upload.addEventListener('load',function(){
                console.log('jq upload onload');
            });
            xhr.addEventListener('load',function(){
                console.log('jq omload.');
            })
            return xhr;
        }
    }
})
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

jq上传结果如下所示: 
Ajax总结_第9张图片

ajax请求二进制文件


FileReader


处理二进制文件主要使用的H5的FileReader。 
Ajax总结_第10张图片

以下是API: 
Ajax总结_第11张图片

ajax请求二进制图片并预览


var xhr = new XMLHttpRequest(),
    url = "http://louiszhai.github.io/docImages/ajax01.png";
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.onload = function(){
  if(this.status == 200){
    var blob = this.response;
    var img = document.createElement("img");
    //方案一
    img.src = window.URL.createObjectURL(blob);//这里blob依然占据着内存
    img.onload = function() {
      window.URL.revokeObjectURL(img.src);//释放内存
    };
    //方案二
    //var reader = new FileReader();
    reader.readAsDataURL(blob);//FileReader将返回base64编码的data-uri对象
    reader.onload = function(){
      img.src = this.result;
    }*/
    //方案三
    //img.src = url;//最简单方法
    document.body.appendChild(img);
  }
}
xhr.send();
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

ajax请求二进制文本并展示


var xhr = new XMLHttpRequest();
xhr.open("GET","http://localhost:8080/Information/download.jsp?data=node-fetch.js");
xhr.responseType = "blob";
xhr.onload = function(){
  if(this.status == 200){
    var blob = this.response;
    var reader = new FileReader();
    reader.readAsBinaryString(blob);//该方法已被移出标准api,建议使用reader.readAsText(blob);
    reader.onload=function(){
      document.body.innerHTML = "
" + this.result + "
"
; } } } xhr.send();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

有关二进制文件的读取, 请移步这篇博客http://www.cnblogs.com/jscode/archive/2013/04/27/3572239.html

如何等待多个ajax请求完成


原生js可以使用ES6新增的普若迷斯(Promise). ES6的Promise基于Promises/A+规范(该部分 Fetch入门指南 一文也有提及). 
这里先提供一个解析responses的函数.

function todo(responses){
  responses.forEach(function(response){
    response.json().then(function(res){
      console.log(res);
    });
  });
}
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

原生js使用 Promise.all 方法. 如下:

var p1 = fetch("http://localhost:10108/test1"),
    p2 = fetch("http://localhost:10108/test2");
Promise.all([p1, p2]).then(function(responses){
  todo(responses);
  //TODO do somethings
});
//"test1"
//"test2"
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

jquery可以使用$.when方法. 该方法接受一个或多个Deferred对象作为参数, 只有全部成功才调用resolved状态的回调函数, 但只要其中有一个失败,就调用rejected状态的回调函数. 其实, jq的Deferred是基于 Promises/A规范实现, 但并非完全遵循. (传送门: jQuery 中的 Deferred 和 Promises (2) ).

var p1 = $.ajax("http://localhost:10108/test1"),
    p2 = $.ajax("http://localhost:10108/test2");
$.when(p1, p2).then(function(res1, res2){
  console.log(res1);//["test1", "success", Object]
  console.log(res2);//["test2", "success", Object]
  //TODO do somethings
});
   
   
     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如上, $.when默认返回一个jqXHR对象, 可以直接进行链式调用. then方法的回调中默认传入相应的请求结果, 每个请求结果的都是数组, 数组中依次是responseText, 请求状态, 请求的jqXHR对象.

ajax与history的兼容

你可能感兴趣的:(java基础)