ajax的底層實現


Ajax 技術核心是 XMLHttpRequest 對象(簡稱 XHR),這是由微軟首先引入的一個特性,其他瀏覽器提供商后來都提供了相同的實現。在 XHR 出現之前,Ajax 式的通信必須借助一些手段來實現,大多數是使用隱藏的框架或內嵌框架。XHR 的出現,提供了向服務器發送請求和解析服務器響應提供了流暢的接口。能夠以異步方式從服務器獲取更多的信息,這就意味着,用戶只要觸發某一事件,在不刷新網頁的情況下,更新服務器最新的數據。雖然 Ajax 中的 x 代表的是 XML,但 Ajax 通信和數據格式無關,也就是說這種技術不一定使用 XML。IE7+、Firefox、Opera、Chrome 都支持原生的 XHR 對象,在這些瀏覽器中創建 XHR 對象可以直接實例化 XMLHttpRequest 即可。

var xhr = new XMLHttpRequest();
alert(xhr); //XMLHttpRequest

了解:較老的 IE 版本創建 Microsoft.XMLHTTP 對象:
var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");

在使用 XHR 對象時,先必須調用 open()方法,它接受三個參數:要發送的請求類型(get、post)、請求的 URL 和表示是否異步。open()方法並不會真正發送請求,而只是啟動一個請求以備發送。通過 send()方法進行發送請求,send()方法接受一個參數,作為請求主體發送的數據。如果不需要則,必須填 null。執行 send()方法之后,請求就會發送到服務器上。
當請求發送到服務器端,收到響應后,響應的數據會自動填充 XHR 對象的屬性。那么一共有四個屬性:

接受響應之后,第一步檢查 status 屬性,以確定響應已經成功返回。一般情況 HTTP 狀態代碼為 200 作為成功的標志。除了成功的狀態代碼,還有一些別的:

 

我們判斷 HTTP 狀態值即可,不建議使用 HTTP 狀態說明,因為在跨瀏覽器的時候,可能會不太一致。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
<script>
var xhr=new XMLHttpRequest();
console.log(xhr);

xhr.open("get","test.json?uname=zs",false)
xhr.send(null);
if(xhr.status==200){
    var text=xhr.responseText;
    console.log(text);
}
</script>
</html>

同步調用固然簡單,但使用異步調用才是我們真正常用的手段。使用異步調用的時候,檢測 readyState 屬性,每當 readyState 屬性改變時,觸發readystatechange 事件。這個屬性有五個值:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
<script type="text/javascript">
    var xhr=new XMLHttpRequest()
    console.log(xhr);
    console.log(xhr.readyState);
    
    xhr.open("get","test.json?liu=feng",true);
    console.log(xhr.readyState);
    
    xhr.send(null);
    xhr.onreadystatechange=function(){
        console.log(xhr.readyState);
        if(xhr.readyState==4){
            if(xhr.status==200){
                var text=xhr.responseText;
                console.log(text)
            }
        }
    }
    
</script>
</html>

在提供服務器請求的過程中,有兩種方式,分別是:GET 和 POST。在 Ajax 使用的過程中,GET 的使用頻率要比 POST 高。
GET  請求
GET 請求是最常見的請求類型,最常用於向服務器查詢某些信息。必要時,可以將查詢字符串參數追加到 URL 的末尾,以便提交給服務器xhr.open('get','diner/login?'+'name=Lee&age=100',true);通過 URL 后的問號給服務器傳遞鍵值對數據,服務器接收到返回響應數據。特殊字符傳參產生的問題可以使用 encodeURIComponent()進行編碼處理,中文字符的返回及傳參,可以將頁面保存和設置為 utf-8 格式即可,AJAX 返回的數據為 UTF-8

/一個通用的 URL 提交函數
function addURLParam(url, name, value) {
//判斷的 url 是否有已有參數
url += (url.indexOf('?') == -1 ? '?' : '&'); 
url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
return url;
}

當沒有 encodeURIComponent()方法時,在一些特殊字符比如“&”,會出現錯誤導致無法獲取。

POST  請求
POST 請求可以包含非常多的數據,我們在使用表單提交的時候,很多就是使用的 POST 傳輸方式。
xhr.open('post', 'diner/login', true);
而發送 POST 請求的數據,不會跟在 URL 的尾巴上,而是通過 send()方法向服務器提交數據。
xhr.send('name=Lee&age=100');
一般來說,向服務器發送 POST 請求由於解析機制的原因,需要進行特別的處理。因為POST請求和Web表單提交是不同的,需要使用XHR來模仿表單提交。
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
從性能上來講 POST 請求比 GET 請求消耗更多一些,用相同數據比較,GET最多比 POST 快兩倍。

三、封裝 Ajax
因為 Ajax 使用起來比較麻煩,主要就是參數問題,比如到底使用 GET 還是
POST;我們需要封裝一個 Ajax 函數,來方便我們調用。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
<script>
var obj={
    url:"user",
    data:{name:"zs",age:18},
    async:true,
    success:function(result){
        console.log(result);
        console.log(JSON.parse(result));
    },
    error:function(result){
        console.log(result);
    }
};

ajax(obj);

function ajax(obj){
    var xhr=new XMLHttpResquest();
    obj.data=params(obj.data);
    if(obj.method.toUpperCase()=="GET"){
        obj.url+=(obj.method.indexOf("?")==-1)? "?" +obj.data:"&"+obj.data;
        xhr.open(obj.mehod,obj.url,obj.async);
        xhr.send(null);
    }else{
        xhr.open(obj.method,obj.url,obj.async);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencode");
        xhr.send(obj.data);
    }
    if(obj.async){
        xhr.onreadystatechange=function(){
            if(xhr.readyState==4){
                callback();
            }
        }
    }else{
        callback;
    }
}

function callback(){
    if(xhr.status==200){
        obj.success(xhr.responseText);
        
    }else{
        obj.error("請求失敗!"+xhr.status+xhr.statusText)
    }
}
function params(data){
    var arr=[];
    if(data!= null && !=""){
        for(var d in data){
            var name=encodeURICompoent(d);
            var value=encodeURICompoent(data[d]);
            arr.push(name+"="+value);
        }
        var param=arr.join("&");
        return param;
    }
    return null;
}
</script>
</html>
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;

/**
 * Servlet implementation class servlet01
 */
@WebServlet("/s01")
public class servlet01 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
     */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("servlet");
        Map<String, Object> map= new HashMap<>();
        map.put("uname", "zs");
        map.put("age", 18);
        map.put("sex", true);
        String json=JSON.toJSONString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(json);
    }

}

封裝 Ajax 並不是一開始就形成以上的形態,需要經過多次變化而成。
同步:
提交請求->等待服務器處理->處理完畢返回這個期間客戶端瀏覽器不能干任何事。一心一意,當前只能做一件事,其他事情必須等當前的事情完成,才能繼續后面的事情。
異步:
請求通過事件觸發->服務器處理(這時瀏覽器仍然可以做其他事情)->處理完畢 。三心二意:同時可以做多件事情:左手按着空格鍵,右手可以不斷的擊打鼠標,眼睛還要同時看着屏幕,很辛苦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM