简单介绍不用库(框架)自己写ajax
平常会使用ajax来请求数据,加载一个库(框架),或许仅仅maybe就使用了它的ajax部分。
写个ajax,一来可以经历一下处理问题的过程,提升技术能力,二来工作中有时真的用不着这么大的一个库(框架),用自己写的,何乐不为呢。
先来看看流行的jquery是怎样调用ajax的
$.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(){} //请求完成之后(不论成功或失败) });
这样的调用是不是很舒适、方便,如果感觉舒适那自己动手写也参照这种设计方式,不用太复杂,满足所需就好。
先了解ajax的基础知识
xmlhttprequest 对象
xmlhttprequest对象是ajax的核心,通过xmlhttprequest对象来向服务器发异步请求,从服务器获得数据,所有现代浏览器(ie7+、firefox、chrome、safari、opera)均支持 xmlhttprequest 对象(ie5 和 ie6 使用 activexobject)。
创建一个兼容的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 对象的 responsetext 或 responsexml 属性获得来自服务器的响应。
如果来自服务器的响应是 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中请求了 (在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差不多分析完了,根据实际需要,添加各种功能,去思考每种功能是怎样实现的,并能找到解决方法。
以上内容就是小编跟大家分享的不用库(框架)自己写ajax,希望大家喜欢。
上一篇: ajax请求Session失效问题