不用库(框架),自己写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中请求了 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差不多分析完了,根据实际需要,添加各种功能,去思考每种功能是怎样实现的,并能找到解决方法。
如果都是用现成库(框架),技术谈何进步呢?
不用库(框架),自己写ajax的更多相关文章
- 不借助jquery封装好的ajax,你能用js手写ajax框架吗
不借助jquery封装好的ajax,你能手写ajax框架吗?最基础的ajax框架,一起来围观吧. .创建XMLHttpRequest对象 var xhr = new XMLHttpRequest(); ...
- .net学习之Session、Cookie、手写Ajax代码以及请求流程
1.IIS 7 以上版本集成了两种模式,一种是经典模式,一种是集成模式(直接将asp.net框架集成到IIS中) 2.浏览器和服务器端通过什么技术来实现的?Socket(套接字),通信的语法是HTTP ...
- php--yii框架中的ajax分页与yii框架自带的分页
要想使用Yii分页类 第一步:在控制器层加载分页类 use yii\data\Pagination; 第二步: 使用model层查询数据,并用分分页,限制每页的显示条数 $data = Zhao::f ...
- 现在流行什么 JS库/框架?
现在大家最感兴趣的 JS 库和框架是什么? jQuery 91.5% Underscore 38.6% AngularJS 28.5% Backbone 18.6% React 15.7% Knock ...
- 【STM32H7教程】第12章 STM32H7的HAL库框架设计学习
完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第12章 STM32H7的HAL库框架设计学 ...
- 使用PHP写ajax接口
使用PHP写ajax接口 之前有学过php都是前后端没有分离的,所以也想去了解后端是怎么写出ajax接口的,可能问了别人或者上网找了很多资料都很有有点懵,或者说直接用TP或者lavarel这些后端框架 ...
- TP框架---thinkphp使用ajax
thinkphp使用ajax和之前使用ajax的方法一样,不同点在于之前的ajax中的url指向了一个页面,而thinkphp里面的url需要指向一个操作方法. 一.thinkphp使用ajax返回数 ...
- QT就是别人好心帮你做一些枯燥,并且很重复的代码编写工作,让你更好的把精力投入到你界面的逻辑和功能的实现的功能库(否则写了上万行代码了,才写出个BUG一大堆的毛坯)
好了,现在开始记录我学习QT的学习历程 . 本人也不是计算机专业出来的,自学了一点,但还是不好找工作,于是参加了培训,虽然感觉没多学到什么 编程的学习生涯就是不断的看别人的源码,然后自己参考着写写自己 ...
- 10个优秀的 Web UI库/框架
UI(User Interface)即用户界面,也称人机界面.是指用户和某些系统进行交互方法的集合,实现信息的内部形式与人类可以接受形式之间的转换.本文为WUI用户整理了10个优秀的 Web UI 库 ...
随机推荐
- 启动和关闭JBoss As 7.1.1脚本
启动和关闭JBoss As 7.1.1,脚本例如以下djboss.sh: #!/bin/sh #JBOSS_HOME JBOSS_HOME=/opt/jboss case "$1" ...
- Codeforces 164 E Compatible Numbers
主题链接~~> 做题情绪:好题,做拉的比赛的时候想了非常久,想到枚举变幻某一位的 0 为 1 .可是每一个数都这样枚举岂不超时的节奏,当时没想到事实上从大到小枚举一次就 ok 了. 解题思路: ...
- Amazon S3数据一致性模型
左右Amazon S3有两种类型的数据的一致性模型的: 最后,一致性和读一致性. 有下面几种行为: 1 写一个新的object,然后開始读它.直到全部的变化都传播完(副本),你才干读到它,否则就是ke ...
- 【十一年】注入框架RoboGuice采用:(Your First Injection into a Custom View class)
上一篇我们简单的介绍了一下RoboGuice的使用([十]注入框架RoboGuice使用:(Your First Testcase)),今天我们来看下自己定义View的注入(Custom View). ...
- nutch搏斗之一
nutch搏斗之一 问题描述: 在用nutch1.0做generate 包括5亿url的crawldb时,它默认按照64M分块,分成777个map task,在运行的后期出现 Could not fi ...
- hdu 折线切割平面 (java)
问题: 仅仅要找到规律问题就攻克了,在做题时应该细致去发现数与数之间的联系. 折线切割平面 Time Limit: 2000/1000 MS (Java/Others) Memory Limit ...
- IOS程序设相关计开发技巧
iOS programming architecture and design guidelines 原文地址:http://blog.mugunthkumar.com/articles/ios-pr ...
- 也说Javascript对象拷贝及疑问
一.浅拷贝 当我们需要将一个对象拷贝至另一个对象时,我们一般会这么实现 function shadowCopy(source,target){ var target=target||{}; for(v ...
- Git在下搭建下环境的工具
(本文稿来自:http://www.open-open.com/news/view/55387) Git是一个快速,可扩展的,分布式的版本控制系统.Git服务器起初是专为Linux开发,后来移植至Wi ...
- leetcode第一刷_Convert Sorted List to Binary Search Tree
好,二叉搜索树粉末登场,有关他的问题有这么几个,给你一个n,如何求全部的n个节点的二叉搜索树个数?能不能把全部的这些二叉搜索树打印出来? 这道题倒不用考虑这么多,直接转即可了,我用的思想是分治,每次找 ...