不用库(框架),本身写ajax

  日常会使用ajax来请求数据,加载一个库(框架),或许仅仅maybe就使用了它的ajax部分。javascript

  写个ajax,一来能够经历一下处理问题的过程,提高技术能力,二来工做中有时真的用不着这么大的一个库(框架),用本身写的,何乐不为呢。php

  先来看看流行的jQuery是怎样调用ajax的html

$.ajax({
	url: 		'test.php', 	//发送请求的URL字符串
	type: 		'GET',			//发送方式 
	dataType: 	'json',			//预期服务器返回的数据类型 xml, html, text, json, jsonp, script
	data: 		'k=v&k=v',		//发送的数据 
	async:		true,			//异步请求 
	cache: 		false, 			//缓存 
	timeout: 	5000,			//超时时间 毫秒
	beforeSend: function(){},	//请求以前
	error: 		function(){},	//请求出错时
	success: 	function(){},	//请求成功时
	complete: 	function(){} 	//请求完成以后(不论成功或失败)
});

   这样的调用是否是很温馨、方便,若是感受温馨那本身动手写也参照这种设计方式,不用太复杂,知足所需就好java

  解ajax的基础知识ajax

  XMLHttpRequest 对象数据库

  XMLHttpRequest对象是ajax的核心,经过XMLHttpRequest对象来向服务器发异步请求,从服务器得到数据,全部现代浏览器(IE7+、Firefox、Chrome、Safari、Opera)均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。  json

  建立一个兼容的XMLHttpRequest对象跨域

var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); 

   向服务器发送请求浏览器

xhr.open(method,url,async);
	//method:请求的类型;GET 或 POST
	//url:请求的URL
	//async:true(异步)或 false(同步)
xhr.send(string);
	//将请求发送到服务器
	//string:仅用于 POST 请求

//GET 比 POST 请求方式更简单也更快,而且在大部分状况下都能用
//在如下状况中,请使用 POST 请求:
	//没法使用缓存文件(更新服务器上的文件或数据库)
	//向服务器发送大量数据(POST 没有数据量限制)
	//发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

  服务器响应缓存

  使用 XMLHttpRequest 对象的 responseTextresponseXML 属性得到来自服务器的响应。

    若是来自服务器的响应是 XML,并且须要做为 XML 对象进行解析,请使用 responseXML 属性。

    若是来自服务器的响应并不是 XML,请使用 responseText 属性,responseText 属性返回字符串形式的响应。

  onreadystatechange 事件

  当请求被发送到服务器时,咱们须要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState 属性存有 XMLHttpRequest 的状态信息。

   XMLHttpRequest 对象的三个重要的属性:

    onreadystatechange  //存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数

    readyState  //存有 XMLHttpRequest 的状态, 从 0 到 4 发生变化     

    • 0: 请求未初始化
    • 1: 服务器链接已创建
    • 2: 请求已接收
    • 3: 请求处理中
    • 4: 请求已完成,且响应已就绪

    status  //200: "OK", 404: 未找到页面

  在 onreadystatechange 事件中,咱们规定当服务器响应已作好被处理的准备时所执行的任务, 当 readyState等于4 且 status为200 时,表示响应已就绪

xhr.onreadystatechange = function(){
    if( xhr.readyState == 4 && xhr.status == 200 ){
		//准备就绪 能够处理返回的 xhr.responseText 或者 xhr.responseXML 
	}
};

   一个简单的ajax请求以下:

var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.onreadystatechange = function(){
    if( xhr.readyState == 4 && xhr.status == 200 ){
		//准备就绪 能够处理返回的 xhr.responseText 或者 xhr.responseXML 
	}
};
xhr.open(method,url,async);
xhr.send(string);

   补充:1. 发送GET请求时可能获得的是缓存的结果,为了不这种状况,能够向URL 添加一个惟一的 ID,时间戳。2. 若是须要像HTML表单那样 POST 数据,使用 setRequestHeader() 来添加 HTTP 头。而后在 send() 方法中发送数据。

url += (url.indexOf('?') < 0 ? '?' : '&') + '_='+ (+new Date());
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

  开始写本身的ajax

  先写一个基本的,定义好各类参数选项,供参考

var $ = (function(){
	//辅助函数 序列化参数 
	function param(data){
	    //..	
	}

	function ajax(opts){
		var _opts = {
			url 	   :  '/',  			//发送请求URL地址
			type       :  'GET', 			//发送请求的方式 GET(默认), POST
			dataType   :  '',				//预期服务器返回的数据类型 xml, html, text, json, jsonp, script
			data 	   :  null,				//发送的数据 'key=value&key=value', {key:value,key:value}   
			async	   :  true,				//异步请求 ture(默认异步), false
			cache	   :  true, 			//缓存 ture(默认缓存), false 
			timeout    :  5, 				//超时时间 默认5秒
			load 	   :  function(){}, 	//请求加载中
			error      :  function(){},		//请求出错时
			success    :  function(){},		//请求成功时
			complete   :  function(){}		//请求完成以后(不论成功或失败)
		}, aborted = false, key,
		xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
		for(key in opts) _opts[key] = opts[key];				
		
		/*
		if(_opts.dataType.toLowerCase() === 'script'){
			//..
		}
		if(_opts.dataType.toLowerCase() === 'jsonp'){
			//..
		}
		*/
		if(_opts.type.toUpperCase() === 'GET'){
	    	if(param(_opts.data) !== ''){
	       		_opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + param(_opts.data);
	        }
	        !_opts.cache && ( _opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + '_='+(+new Date()) );
	    }

	    function checkTimeout(){
			if(xhr.readyState !== 4){
				aborted = true;
				xhr.abort();
		  	}
		}
		setTimeout(checkTimeout, _opts.timeout*1000);
		
		xhr.onreadystatechange = function(){
	    	if( xhr.readyState !== 4 ) _opts.load && _opts.load(xhr);
		    if( xhr.readyState === 4 ){
		    	var s = xhr.status, xhrdata;
				if( !aborted && ((s >= 200 && s < 300) || s === 304) ){
					switch(_opts.dataType.toLowerCase()){
			    		case 'xml':
			    			xhrdata = xhr.responseXML;
			    		break;
			    		case 'json':
			    			xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')');
			    		break;
			    		default:
			    			xhrdata = xhr.responseText;
			    	}
					_opts.success && _opts.success(xhrdata,xhr);
				}else{
					_opts.error && _opts.error(xhr);
				}
				_opts.complete && _opts.complete(xhr);
	    	}
	    };		
	    xhr.open(_opts.type,_opts.url,_opts.async);
	    if(_opts.type.toUpperCase() === 'POST'){
	        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
	    }
	    xhr.send(_opts.type.toUpperCase() === 'GET' ? null : param(_opts.data));
	}
	return {
		ajax: ajax
	}
})();

   定义好了参数选项,来分析一下。其中 dataType 是整个ajax的重点,代码的简单或者复杂都在它了。

  在这里dataType为预期服务器返回的数据类型:xml, html, text, json, jsonp, script

  1. 为xml时,来自服务器的响应是XML,使用 responseXML 属性获取返回的数据

  2. 为html、text、json时,使用 responseText 属性获取返回的数据

      a. 为html时,返回纯文本HTML信息,其中包含的script标签是否要在插入dom时执行 ( 代码复杂度+3 )

      b. 为json时,  返回JSON数据,要安全、要便捷、要兼容  ( 代码复杂度+2 )

  3. 为jsonp时,通常跨域才用它,不用原来的ajax请求了,用建立script法( 代码复杂度+2 )

  4. 为script时:  要跨域时,不用原来的ajax请求了,用建立script法( 代码复杂度+1 ); 不跨域,返回纯文本JavaScript代码, 使用 responseText 属性获取返回的数据 ( 代码复杂度+1 )

  其中,在html片断中的script标签、jsonp、script,都要用到建立script标签的方式。

  处理dataType为json

xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')');

  这是最简单的处理方式了,要JSON兼容,能够用json2.js。

  处理dataType为jsonp

  jsonp是要经过script标签来请求跨域的,先了解下流程:

     

  这上图中 a.html中请求了 http://www.b.com/b.php?callback=add  (在ajax程序中请求url就是这个连接),在b.php中读取了传过来的参数 callback=add  根据获取到的参数值(值为add),以JS语法生成了函数名,并把json数据做为参数传入了这个函数,返回以JS语法生成的文档给a.html,a.html解析并执行返回的JS文档,调用了定义好的add函数。

   在程序中通常采用更通用的方式去调用,好比下面这个普遍使用的loadJS函数:

function loadJS(url, callback) {
	var doc = document, script = doc.createElement('script'), body = doc.getElementsByTagName('body')[0];
	script.type = 'text/javascript';
	if (script.readyState) {  
		script.onreadystatechange = function() {
			if (script.readyState == 'loaded' || script.readyState == 'complete') {
				script.onreadystatechange = null;
				callback && callback();
			}
		};
	} else {  
		script.onload = function() {
			callback && callback();
		};
	}
	script.src = url;
	body.appendChild(script);
}

  这样把请求的url,传入loadJS函数,获得同样的结果。

loadJS('http://www.b.com/b.php?callback=add');

  由于是动态建立script,请求成功返回,JS代码就当即执行,若是请求失败是没有任何提示的。所以自定义的参数选项: _opts.success 能调用,_opts.error不能调用。

  ajax处理jsonp也有两种状况:

  1. 设置了请求URL后的参数 callback=add 特别是定义了函数名add,请求成功返回,JS代码就当即执行(这里就是调用 add({"a":8,"b":2})  )

  2. 在_opts.success中处理JSON数据,就是请求成功返回,JS代码不执行,并把函数中的参数挪出来,做为_opts.success的参数返回( 这里至关于处理字符串 'add({"a":8,"b":2})' ,去掉 'add(' 和 ‘)’,获得 {"a":8,"b":2} )

  处理dataType为html

   若是不处理HTML片断中script标签,直接把responseText返回值插入DOM树就能够了。若是要处理script,就要把HTML片断中的script标签找出来,对买个script单独处理,并注意是script标签中包含的JS代码仍是经过src请求的。

  处理dataType为script

  若是要跨域时,用建立script的方式,和处理jsonp相似; 不跨域,使用 responseText 属性获取返回的数据,能够用 eval 来让代码执行,也能够建立script来执行。

function addJS(text) {
	var doc = document, script = doc.createElement('script'), head = doc.getElementsByTagName('body')[0];
	script.type = 'text/javascript';
	script.text = text;
	body.appendChild(script);
}

  到此ajax差很少分析完了,根据实际须要,添加各类功能,去思考每种功能是怎样实现的,并能找到解决方法。

    若是都是用现成库(框架),技术谈何进步呢?

相关文章
相关标签/搜索