AJAX入新手入門實例講解
本文參考或借鑑一些公開資料,特此說明。
AJAX( Asynchronous JavaScript and XML,異步的 JavaScript 和 XML),不是新的編程語言,而是一種使用現有標準的新方法。AJAX 最大的優點是在不重新加載整個頁面的情況下,可以與服務器交換數據並更新部分網頁內容。
同步的概念
同步,我的理解是一種線性執行的方式,執行的流程不能跨越。一般用於流程性比較強的程序,我們做的用戶登錄功能也是同步處理的,必須用戶通過用戶名和密碼驗證後才能進入系統的操作。同步可以看做是一個單線程操作,只要客戶端請求了,在服務器沒有反饋信息之前是一個線程阻塞狀態。
異步的概念
異步,是一種並行處理的方式,不必等待一個程序執行完,可以執行其它的任務。異步肯定是個多線程。在客戶端請求時,可以執行其他線程,並且在把這個線程存放在他的隊列裏面,有序的執行。在JavaScript中實現異步的方式主要有Ajax和H5新增的Web Worker。
而ajax就可以讓我們實現這裏所說的異步請求。
簡單地說,同步交互:客戶端發出一個請求後,需要等待服務器響應結束後,才能發出第二個請求;異步交互:客戶端發出一個請求後,無需等待服務器響應結束,就可以發出第二個請求。
AJAX主要是實現頁面和 web 服務器之間數據的異步傳輸,因此學習練習使用AJAX需要使用Web服務器。
XMLHttpRequest 工作原理
傳統的web前端與後端的交互中,瀏覽器直接訪問Tomcat的Servlet來獲取數據。Servlet通過轉發把數據發送給瀏覽器。
當我們使用AJAX之後,瀏覽器是先把請求發送到XMLHttpRequest異步對象之中,異步對象對請求進行封裝,然後再與發送給服務器。服務器並不是以轉發的方式響應,而是以流的方式把數據返回給瀏覽器。
XMLHttpRequest異步對象會不停監聽服務器狀態的變化,得到服務器返回的數據,就寫到瀏覽器上,因爲不是轉發的方式,所以是無刷新就能夠獲取服務器端的數據。
使用js發起一個ajax請求過程,圖示如下:
說明:js發起一個ajax請求過程
首先let xhr = new XMLHttpRequest();,新建一個XMLHttpRequest對象。此時xhr對象的readyState=0,表示請求未初始化。
您需要調用xhr.open(method,url,async),告訴xhr請求的方式,URL,同步or異步,讓其初始化。如果執行完了這句,xhr.readyState=1,表示連接已經建立好了。
但是,如果您想發出請求,您就需要調用xhr.send()方法,如果是POST請求,您需要設置send()的參數,send(data)。調用過xhr.send()後,xhr.readyState就變成了2,請求已接收狀態,或者說我們已經發出了請求。
後面的幾個狀態,就不需要我們通過代碼去改變他了。我們的請求會通過網絡,到達指定服務器,服務器響應後,再通過網絡返回給我們。這個狀態,我們也無法通過代碼去改變。但是我們可以通過監聽函數onreadystatechange去獲取請求傳輸的進度。
當我們受到第一個字節開始,xhr.readyState=3。
在接收完全部響應數據後,請求完成,此時xhr.readyState=4。
之後處理……。
爲對上面介紹有一個感性認識,下面是一個比較完整而簡單的示例
包含兩個文件(放在同一目錄中):
一個名爲demo.txt的文本文件,內容如下:
呵呵,這是來自demo.txt的內容
一個名爲demo.html的網頁文件,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
function loadXMLDoc(){
var xmlhttp;
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}
else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("show").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","demo.txt",true);
xmlhttp.send();
}
window.οnlοad=function(){
var obt=document.getElementById("bt");
obt.οnclick=function(){
loadXMLDoc();
}
}
</script>
</head>
<body>
<div id="show">
<h2>原來的內容</h2>
</div>
<input type="button" id="bt" value="查看效果"/>
</body>
</html>
用瀏覽器打開demo.html的網頁文件,點擊按鈕讀入demo.txt文本中的內容,參見下圖:
創建 XMLHttpRequest 對象的語法:
variable=new XMLHttpRequest();
XMLHttpRequest對象的常見屬性如下:
屬性 |
描述 |
onreadystatechange |
存儲函數(或函數名),每當readyState的屬性改變時,就會調用該函數。 |
readyState |
存有的XMLHttpRequest的狀態從0到4發生變化。 |
reponseText |
以文本形式返回響應。 |
responseXML |
以XML格式返回響應 |
status |
將狀態返回爲數字(例如,“Not Found”爲404,“OK”爲200) |
statusText |
以字符串形式返回狀態(例如,“Not Found”或“OK”) |
XMLHttpRequest對象的方法
XMLHttpRequest對象的重要方法如下:
方法 |
描述 |
abort() |
取消當前請求。 |
getAllResponseHeaders() |
以字符串形式返回完整的HTTP標頭集。 |
getResponseHeader( headerName ) |
返回指定HTTP標頭的值。 |
void open(method,URL) |
打開指定獲取或交的方法和URL的請求。 |
void open(method,URL,async) |
與上面相同,但指定異步或不。 |
void open(method,URL,async,userName,password) |
與上面相同,但指定用戶名和密碼。 |
void send(content) |
發送獲取請求。 |
setRequestHeader( label,value) |
將標籤/值對添加到要發送的HTTP標頭。 |
下面給出實例
例1、利用ajax讀取xml文件中的數據
本例使用了兩個文件,一個是data.xml——充當服務端,一個是ajaxTest.html——充當客戶端。都可以用記事本建立,注意文件名的後綴(擴展名)。放在一個文件夾中。
data.xml內容如下:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data>
這是一些樣本數據……它存儲在XML文件中,並由JavaScript檢索。
</data>
</root>
ajaxTest.html內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用Ajax開發Web應用程序之示例</title>
<script type="text/javascript">
<!--
//此函數將在電擊"View XML data"鏈接的時候執行
function ajaxRead(file){
//xmlObj,負責客戶端和服務器中轉
var xmlObj=null;
/*
測試不同對象的可用性
不同的瀏覽器執行XMLHttpRequest對象的時候不同,所以定義"xmlObj"作爲XMLHttpRequest對象的時候,必須區別對待
如果沒有XMLHttpRequest可用,函數以return結束來取消錯誤報告
*/
if(window.XMLHttpRequest){
xmlObj=new XMLHttpRequest();
}else if(window.ActiveXObject){
xmlObj=new ActiveXObject("Microsoft.XMLHTTP");
}else{
return;
}
/*
每當XMLHttpRequest狀態改變時,onreadystatechange事件就觸發
此事件共有5個狀態,從0到4
[0]uninitialized未初始化(在XMLHttpRequest開始前)
[1]loading(一旦初始化)
[2]loaded(一旦XMLHttpRequest從服務器獲得響應)
[3]interactive(當對象連接到服務器)
[4]complete(完成)
*/
/*
readyState()方法用來獲得當前XMLHttpRequest的狀態
狀態5[編號4]是用來確認數據是否可用的,如果"是",則執行updateObj方法
此方法有2個參數:ID,填充的數據
*/
/*
xmlObj.responseXML屬性是一個DOM對象,對於XML文件來說,它有點像網頁中的"document"對象
通過getElementsByTagName可以獲得XML文件中的任何節點
xmlObj.responseXML.getElementsByTagName('data')[0]是獲得第1個名稱爲"data"的節點
它返回XML節點,無數據的---得到節點裏的數據必須通過訪問此節點的屬性
firstChild.data
(firstChild獲得<data>節點之間的文本節點,而"data"屬性則是文本節點的實際文本)
*/
/*
xmlObj.open('GET',file,true);
xmlObj.send('');
這是ajaxRead函數中的最後一塊
xmlObj的open方法打開一個通往服務器的連接(通過一個特殊的協議,這裏指定爲"GET"---也可以使用"POST"或其他)
請求一個文件(在這裏,file變量---data.xml,是當作參數發送給了ajaxRead函數)
並且JavaScript可以操控這個請求是否爲同步(false)或者異步(true,默認)
這是異步JavaScript和XML,將可以使用默認的異步方法---當使用同步之後,這個程序將不能運行
xmlObj.send('');
簡單的發送了一個空字符串給服務器
如果沒有這一行,xmlObj的readystate的值將不能爲4,使得頁面將不能更新
這個發送方法可以被用於其它東西,但是此程序僅僅從服務器得到數據,並沒有發送數據給服務器,所以就到此爲止
*/
xmlObj.onreadystatechange=function(){
if(xmlObj.readyState==4){
updateObj('xmlObj',xmlObj.responseXML.getElementsByTagName('data')[0].firstChild.data);
}
}
xmlObj.open('GET',file,true);
xmlObj.send('');
}
/*
此函數更新在當前頁有新值的其他任何元素
第1個參數,"obj",是當前頁中一個元素的id---這是被更新的對象
第2個參數,"data",指明瞭將要替換"obj"對象的一個新的字符串
正常地,它是一個檢查並且確認當前頁有含有id值爲"obj"的元素的很好的方法
*/
function updateObj(obj,data){
//document.getElementById(obj).firstChild.data = data;
document.getElementById(obj).innerHTML=data;
}
//-->
</script>
</head>
<body>
<h1>用Ajax開發Web應用</h1>
<p id="xmlObj">
<a href="data.xml" title="查看XML數據" οnclick="ajaxRead('data.xml');this.style.display='none';return false">查看XML數據</a>
</p>
</body>
</html>
用瀏覽器打開這個頁面(雙擊ajaxTest.html文件即可),結果如下所示:
要創建AJAX實例,需要使用服務器端,在這裏使用data.xml相當於服務器端上的文件。
前面提到過,AJAX主要是實現頁面和 web 服務器之間數據的異步傳輸,學習練習使用AJAX需要使用Web服務器,因此要想深入學習,就需要搭建Web服務器。
搭建Web服務器
Web服務器一般指網站服務器,是指駐留於因特網上某種類型計算機的程序,可以向瀏覽器等Web客戶端提供文檔,也可以放置網站文件,讓全世界瀏覽;可以放置數據文件,讓全世界下載。常見Web服務器有Apache+PHP+MySQL。在這裏我們使用nodejs+express搭建web服務器。
先安裝先安裝nodejs,進入下面這個nodejs中文網鏈接 下載nodejs
選擇對應的版本然後下載安裝(比較簡單就不多說了,如有疑惑可以百度),完了驗證下nodejs安裝是否成功。輸入node -v命令查看版本:
測試nodejs原生的HTTP服務器
新建一個目錄(也稱爲文件夾),例如在D:\NodeTest下新建一個myServer文件夾,在這個目錄中新建(可用記事本)一個serverA.js文件(文件名你自定,只要擴展名是.js就行),寫入如下代碼:
var http = require("http"); //導入http模塊
//開啓一個監聽事件,每次HTTP請求都會觸發這個事件
http.createServer(function(req, res){ //req用戶請求信息 res服務器響應信息
res.write('<head><meta charset="utf-8"/></head>'); //設置編碼
res.write("實驗測試!"); //設置響應體
res.end(); //結束事件
}).listen(3000); //設置監聽端口號
// 終端打印如下信息
console.log('Server running at http://127.0.0.1:3000 or http://localhost:3000 ');
用node 命令執行
在cmd中輸入 node D:\NodeTest\serverA.js
啓動服務,如下所示:
打開瀏覽器訪問 http://127.0.0.1:3000 或 http://localhost:3000,如下所示:
簡單例子運行成功了,這其實是用node.js搭建了一個服務器,然後來監聽端口的訪問事件,最後做出相應的迴應,需要指出的是,當我們關閉CMD或按CTRL+C鍵之後服務就關閉了。如果修改了nodejs服務器端的代碼,都需要重啓服務器纔會生效。
在此基礎上,就可以使用nodejs服務器
例、有註冊和登錄功能的服務器
建立一個目錄D:\AJAXTest2,再在此建立一個www目錄,將server.js放入AJAXTest2目錄,
將user.html和ajax.js放入www目錄,參見下圖:
server.js內容如下:
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
const urlLib = require('url');
var users = {};
var server = http.createServer(function (req, res) {
//解析數據
var str = '';
req.on('data', function (data) {
str += data;
});
req.on('end', function () {
var obj = urlLib.parse(req.url, true);
const url = obj.pathname;
const GET = obj.query;
const POST = querystring.parse(str);
//區分——接口、文件
if (url == '/user') { //接口
switch (GET.act) {
case 'reg':
//1.檢查用戶名是否已經有了
if (users[GET.user]) {
res.write('{"ok": false, "msg": "此用戶已存在"}');
} else {
//2.插入users
users[GET.user] = GET.pass;
res.write('{"ok": true, "msg": "註冊成功"}');
}
break;
case 'login':
//1.檢查用戶是否存在
if (users[GET.user] == null) {
res.write('{"ok": false, "msg": "此用戶不存在"}');
//2.檢查用戶密碼
} else if (users[GET.user] != GET.pass) {
res.write('{"ok": false, "msg": "用戶名或密碼有誤"}');
} else {
res.write('{"ok": true, "msg": "登錄成功"}');
}
break;
default:
res.write('{"ok": false, "msg": "未知的act"}');
}
res.end();
} else { //文件
//讀取文件
var file_name = './www' + url;
console.log(file_name);
fs.readFile(file_name, function (err, data) {
if (err) {
console.log(err)
res.write('404');
} else {
res.write(data);
}
res.end();
});
}
});
});
server.listen(8080);
//終端提示
console.log('Server running at http://localhost:8080')
ajax.js內容如下:
function json2url(json){
var arr=[];
for(var name in json){
arr.push(name+'='+json[name]);
}
return arr.join('&');
}
function ajax(json){
json=json || {};
if(!json.url)return;
json.data=json.data || {};
json.type=json.type || 'get';
var timer=null;
if(window.XMLHttpRequest){
var oAjax=new XMLHttpRequest();
}else{
var oAjax=new ActiveXObject('Microsoft.XMLHTTP');
}
switch(json.type){
case 'get':
oAjax.open('GET',json.url+'?'+json2url(json.data),true);
oAjax.send();
break;
case 'post':
oAjax.open('POST',json.url,true);
oAjax.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
oAjax.send(json2url(json.data));
break;
}
oAjax.onreadystatechange=function(){
if(oAjax.readyState==4){
clearTimeout(timer);
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
json.success && json.success(oAjax.responseText);
}else{
json.error && json.error(oAjax.status);
}
}
};
}
user.html內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="ajax.js" charset="utf-8"></script>
<script type="text/javascript">
window.οnlοad=function (){
var oTxtUser=document.getElementById('user');
var oTxtPass=document.getElementById('pass');
var oBtnReg=document.getElementById('reg_btn');
var oBtnLogin=document.getElementById('login_btn');
oBtnLogin.οnclick=function (){
ajax({
url: '/user',
data: {act: 'login', user: oTxtUser.value, pass: oTxtPass.value},
type: 'get',
success: function (str){
var json=eval('('+str+')');
if(json.ok){
alert('登錄成功');
}else{
alert('登錄失敗:'+json.msg);
}
},
error: function (){
alert('通信錯誤');
}
});
};
oBtnReg.οnclick=function (){
ajax({
url: '/user',
data: {act: 'reg', user: oTxtUser.value, pass: oTxtPass.value},
type: 'get',
success: function (str){
var json=eval('('+str+')');
if(json.ok){
alert('註冊成功');
}else{
alert('註冊失敗:'+json.msg);
}
},
error: function (){
alert('通信錯誤');
}
});
};
};
</script>
</head>
<body>
用戶:<input type="text" id="user"><br>
密碼:<input type="password" id="pass"><br>
<input type="button" value="註冊" id="reg_btn">
<input type="button" value="登錄" id="login_btn">
</body>
</html>
先cd到D:\AJAXTest2目錄
cd /d D:\AJAXTest2
啓動 node server.js
瀏覽器訪問localhost:8080/user.html
輸入用戶名和密碼,開始註冊或登錄,試試了。
關於express
express 是nodejs的一個web框架,使用express,能夠更便捷的使用nodejs.
express-generator是express應用生成器,相當於express 的骨架,進入一個web項目中後,使用express projectname命令,能快速構建projectname這個應用的目錄結構。
npm install express --save -g
npm install express-generator --save -g
之後,在找到其所在位置:
現在可以使用express框架構建express項目
在cmd中使用命令:express ‘你的項目名’ -e
其中,-e 表示使用EJS模板。
例如:
express myStudy -e
安裝成功後就可以使用express框架構建項目了,在當前目錄中生成了一個與項目名相同目錄。最後有3個選項,先不深究,意思是:
改變目錄:cd expressDemo
安裝依賴:npm install
運行應用程序:npm start
關於express就不進一步介紹了,感興趣的朋友可以參考他文。
下面介紹jQueryd的Ajax方法。
jQueryd的Ajax方法
$.ajax()方法中的參數很多,我在實例中使用的只是一小部分,這裏只介紹實例中所需要的參數的使用,其餘更多參數還將繼續學習。
$.ajax({
url:"發送請求(提交或讀取數據)的地址",
dataType:"預期服務器返回數據的類型",
type:"請求方式",
async:"true/false",
data:{發送到/讀取後臺(服務器)的數據},
success:function(data){請求成功時執行},
error:function(){請求失敗時執行}
});
說明: 這些參數均爲選填,如果不設置,按默認值處理。
<1> url 默認爲當前頁地址
<2> dataType 可用類型:
(如果不指定,JQuery將自動根據http包mime信息返回responseXML或responseText,並作爲回調函數參數傳遞)
xml:返回XML文檔,可用JQuery處理。
html:返回純文本HTML信息。
script:返回純文本JavaScript代碼。
json:返回json數據。
jsonp:(JSON with Padding) 是 json 的一種"使用模式",可以讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。
text:返回純文本字符串。
說明:對於json和jsonp的區別,本小白暫時沒有深入瞭解,目前只知道jsonp可以跨域讀取數據,有待進一步學習~
<3> type 可用類型主要爲post和get兩種(默認爲get)
get:從指定的資源請求數據(從服務器讀取數據)
post:向指定的資源提交要被處理的數據(向服務器提交數據)
<4> async 異步方式,默認爲true,即異步方式。當設置爲false時,爲同步方式。
異步方式:ajax執行後,會繼續執行ajax後面的腳本,直到服務器端返回數據後,觸發ajax裏的success方法,這時候執行的是兩個線程。
同步方式:在沒有返回值之前,同步請求將鎖住瀏覽器,用戶其它操作必須等待請求完成纔可以執行。
說明:這裏的同步和異步有待深入理解,以下實例均使用默認的異步方式
<5> data 請求的數據,{ }中可以填入多項數據。如果不填(一般爲get請求),則讀取對應地址的全部數據,此時可以在console中通過console.log(res)顯示數據情況。
<6> success 和 error 兩個函數 一般需要設置,方便確定請求是否成功,以及請求成功後的提示或是對數據的處理和顯示。
例、實現在頁面上輸入一個地址,點擊獲取經緯度,彈出該地址的經緯度。
(本例來源:https://blog.csdn.net/Yuan_mingyu/article/details/86748591 )
url=“https://restapi.amap.com/v3/geocode/geo” key:“7486e10d3ca83a934438176cf941df0c”
(此處的key值是從此地址請求數據所需的,爲data數據中的一項,直接使用即可)
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>查詢經緯度</title>
<!-- js部分 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
function showAdress()
{
var str = document.getElementById("text").value;
$.ajax
({
url: "https://restapi.amap.com/v3/geocode/geo",
dataType: "json",
type: "get",
data: {
address: str,
key: "7486e10d3ca83a934438176cf941df0c",
},
success:function(data){
alert(data.geocodes[0].formatted_address+"經緯度:"+data.geocodes[0].location);
console.log(data); //在console中查看數據
},
error:function(){
alert('failed!');
},
});
}
</script>
</head>
<body>
<!-- css部分 -->
<style type="text/css">
.button{
width: 100px;
height: 29px;
font-size: 16px;
color: white;
background-color: black;
padding: 0;
vertical-align: top;
border: 0;
}
.textbox{
height: 25px;
padding: 0;
vertical-align: top;
}
span{
font-size: 16px;
height: 29px;
line-height: 29px;
}
</style>
<p>利用 https://restapi.amap.com/v3/geocode/geo服務 </p>
<!-- div部分 -->
<div>
<form name="form">
<span>輸入地址:</span><input id="text" class="textbox" type="text"/>
<input class="button" type="button" value="獲取經緯度" οnclick="showAdress()"/>
</form>
</div>
</body>
</html>
將上述代碼,保存文件名爲:jQuery的Ajax實例.html。用瀏覽器打開這個頁面(雙擊“jQuery的Ajax實例.html”文件即可),結果如下所示:
AJAX官網:
http://api.jquery.com/category/ajax/
AJAX教程
https://www.softwhy.com/qiduan/ajax_source/