原文見martin的博客
最近重新看《javascript高級程序設計》,突然看到了ajax,想起來之前學習的各種坑,又想著結(jié)合最近學習的模塊化編程、面向?qū)ο笫骄幊?,所以用原生的js采用面向?qū)ο蟮脑O計思路對ajax進行了一個封裝,同時,想起之前學習ajax的最大困難:沒有服務器端代碼,不好測試,所以這次用原生node寫了一個簡單的服務器,用于處理ajax的測試。
綜上,本文主要提供了以下幾個點:
- 采用面向?qū)ο蟮姆椒ㄓ迷鷍s封裝了一個ajax類,更便捷的實現(xiàn)ajax通信
- 提供了一個Node寫的服務器端的代碼,可以用來測試ajax
- 提供了一個demo,服務器端以及瀏覽器端的代碼來測試ajax類
倉庫在這里,服務器,客戶端的代碼都在里面,也有一些測試的說明。
ajax實現(xiàn)原理
ajax是一項偉大的技術,其很好的解決了傳統(tǒng)瀏覽器一言不合就重新發(fā)送整個頁面,速度慢,用戶體驗差的問題。它是一個獲取資源的手段,可以在不進行整體刷新的情況下進行局部dom修改,速度快,用戶體驗好。實現(xiàn)的原理主要是基于一個類,XMLHttpRequest(IE7以下不支持,提供了另外的類進行實現(xiàn),不在本文討論范圍中,都2017年了。。)。
大概的原理分成下面幾步:
- 新建XMLHttpRequest對象,var xhr = new XMLHttpRequest().
- 通信需要有一個回調(diào)函數(shù),就是接收到對方的回信之后需要有一個處理的函數(shù),這個函數(shù)可以通過xhr.onreadystatechange = callback;來進行回調(diào)。對方的回信存儲在xhr.responseText。當通信狀態(tài)xhr.readyState === 4的時候,xhr.responseText就是完整的接收到的數(shù)據(jù)。
- 收到回信,進行相應的dom操作,實現(xiàn)頁面的局部刷新。
可以看到,其實一個ajax的請求,是很簡單簡潔的,只要開發(fā)者提供,method(get還是post),data(要傳遞的數(shù)據(jù),ajax本身是用來通信的嘛),url(通信的對象),callback(收到回信后的處理)就可以完成一次通信,別的地方是重復性的勞動,不必每次都繁瑣的寫一遍。所以我建了一個類,提供send方法,實現(xiàn)信息的發(fā)送(ajax重復性的工作),上述四個數(shù)據(jù)存儲在每個實例中,只要實例調(diào)用send方法,就會進行一次ajax通信。大概的代碼思路是這樣:
function Ajax(obj){
//根據(jù)obj對method,data,url等進行初始化
};
Ajax.prototype.send = function(){
var xhr = new XMLHttpRequest();//新建ajax請求,不兼容IE7以下
xhr.onreadystatechange = function(){//注冊回調(diào)函數(shù)
if(xhr.readyState === 4)
callback(xhr.responseText);
}
if(method === 'get'){//如果是get方法,需要把data中的數(shù)據(jù)轉(zhuǎn)化作為url傳遞給服務器
xhr.open(method,url,true);
xhr.send(null);
}else if(method === 'post'){//如果是post,需要在頭中添加content-type說明
xhr.open(method,url,true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(JSON.stringify(data));//發(fā)送的數(shù)據(jù)需要轉(zhuǎn)化成JSON格式
}else {
console.log('不識別的方法:'+method);
return fasle;
}
}
源碼點擊這里
有了這個類,要實現(xiàn)一條ajax請求,只需執(zhí)行下面代碼即可:
var ajax = new Ajax({
method:'get',//設置ajax方法
url:'http://localhost:3000',//設置通訊地址
callback:function(res){//設置回調(diào)函數(shù)
alert(res)
},
data: data//需要傳遞的數(shù)據(jù)
})
ajax.send();
詳細的關于這個類的使用方法,可以參考這里
有了ajax,要測試,怎么辦?當然可以找網(wǎng)上一些提供接口的網(wǎng)站進行ajax通信,比如聚合數(shù)據(jù),有一些Key需要自己申請,相比之下,自己寫一個服務器端的代碼來處理請求,反而顯得更簡單一點。
服務器端處理ajax請求
node.js出來之后,javascript又能打前端,又能干后端,也把我拉進了坑里。在這里,主要是為了進行測試,所以越簡單越好(我服務器端的代碼水平還不夠)。這里我主要參考了菜鳥教程中關于處理客戶端請求的代碼:原理及介紹點這里
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req,res){
console.log(req.method);
if(req.method==='GET'){//處理get請求
res.writeHead(200,{'content-Type':'text/plain',"Access-Control-Allow-Origin":"*"});
res.end(util.inspect(url.parse(req.url, true)));//處理get請求,并將結(jié)果傳遞給客戶端
}
else{//處理post請求
// 定義了一個post變量,用于暫存請求體的信息
var post = '';
// 通過req的data事件監(jiān)聽函數(shù),每當接受到請求體的數(shù)據(jù),就累加到post變量中
req.on('data', function(chunk){
post += chunk;
});
// 在end事件觸發(fā)后然后向客戶端返回。
req.on('end', function(){
post = JSON.parse(post);
console.log(post);
res.writeHead(200, {'Content-Type': 'text/html',"Access-Control-Allow-Origin":"*"});
res.end(util.inspect(post));
});
}
}).listen(3000);
console.log('server is listening on "3000"');
get請求的處理比較簡單,因為get方法將信息都加在url中,服務器端對url進行解析就可以得到該請求的內(nèi)容,我這里的處理是將其原封不動的返回給客戶端。
post的請求相對麻煩,需要注冊兩個時間,on,end。一個是處理數(shù)據(jù)塊,因為Post請求一般數(shù)據(jù)比較多,分多次傳輸,我們要的其實只是end之后的數(shù)據(jù),在這里我也是直接將其信息幾乎原封不動的返回。
聯(lián)合測試
可以直接clone這里
里面的example下面有兩個文件,一個是客戶端的代碼,一個是服務端的代碼,服務端代碼需要node server.js即可實現(xiàn)監(jiān)聽,瀏覽器端直接打開index.html即可。
總結(jié)
第一次發(fā)這種文章,也是發(fā)現(xiàn)寫一篇文章不容易,在寫的過程中也是有不少收獲,我也深知,我還小,知識還有很多的漏洞,如果有誤,嚴厲指出即可,謝謝!
