平常会使用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 对象的 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差不多分析完了,根据实际需要,添加各种功能,去思考每种功能是怎样实现的,并能找到解决方法。

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

不用库(框架),自己写ajax的更多相关文章

  1. 不借助jquery封装好的ajax,你能用js手写ajax框架吗

    不借助jquery封装好的ajax,你能手写ajax框架吗?最基础的ajax框架,一起来围观吧. .创建XMLHttpRequest对象 var xhr = new XMLHttpRequest(); ...

  2. .net学习之Session、Cookie、手写Ajax代码以及请求流程

    1.IIS 7 以上版本集成了两种模式,一种是经典模式,一种是集成模式(直接将asp.net框架集成到IIS中) 2.浏览器和服务器端通过什么技术来实现的?Socket(套接字),通信的语法是HTTP ...

  3. php--yii框架中的ajax分页与yii框架自带的分页

    要想使用Yii分页类 第一步:在控制器层加载分页类 use yii\data\Pagination; 第二步: 使用model层查询数据,并用分分页,限制每页的显示条数 $data = Zhao::f ...

  4. 现在流行什么 JS库/框架?

    现在大家最感兴趣的 JS 库和框架是什么? jQuery 91.5% Underscore 38.6% AngularJS 28.5% Backbone 18.6% React 15.7% Knock ...

  5. 【STM32H7教程】第12章 STM32H7的HAL库框架设计学习

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第12章       STM32H7的HAL库框架设计学 ...

  6. 使用PHP写ajax接口

    使用PHP写ajax接口 之前有学过php都是前后端没有分离的,所以也想去了解后端是怎么写出ajax接口的,可能问了别人或者上网找了很多资料都很有有点懵,或者说直接用TP或者lavarel这些后端框架 ...

  7. TP框架---thinkphp使用ajax

    thinkphp使用ajax和之前使用ajax的方法一样,不同点在于之前的ajax中的url指向了一个页面,而thinkphp里面的url需要指向一个操作方法. 一.thinkphp使用ajax返回数 ...

  8. QT就是别人好心帮你做一些枯燥,并且很重复的代码编写工作,让你更好的把精力投入到你界面的逻辑和功能的实现的功能库(否则写了上万行代码了,才写出个BUG一大堆的毛坯)

    好了,现在开始记录我学习QT的学习历程 . 本人也不是计算机专业出来的,自学了一点,但还是不好找工作,于是参加了培训,虽然感觉没多学到什么 编程的学习生涯就是不断的看别人的源码,然后自己参考着写写自己 ...

  9. 10个优秀的 Web UI库/框架

    UI(User Interface)即用户界面,也称人机界面.是指用户和某些系统进行交互方法的集合,实现信息的内部形式与人类可以接受形式之间的转换.本文为WUI用户整理了10个优秀的 Web UI 库 ...

随机推荐

  1. 启动和关闭JBoss As 7.1.1脚本

    启动和关闭JBoss As 7.1.1,脚本例如以下djboss.sh: #!/bin/sh #JBOSS_HOME JBOSS_HOME=/opt/jboss case "$1" ...

  2. Codeforces 164 E Compatible Numbers

    主题链接~~> 做题情绪:好题,做拉的比赛的时候想了非常久,想到枚举变幻某一位的 0 为 1 .可是每一个数都这样枚举岂不超时的节奏,当时没想到事实上从大到小枚举一次就 ok 了. 解题思路: ...

  3. Amazon S3数据一致性模型

    左右Amazon S3有两种类型的数据的一致性模型的: 最后,一致性和读一致性. 有下面几种行为: 1 写一个新的object,然后開始读它.直到全部的变化都传播完(副本),你才干读到它,否则就是ke ...

  4. 【十一年】注入框架RoboGuice采用:(Your First Injection into a Custom View class)

    上一篇我们简单的介绍了一下RoboGuice的使用([十]注入框架RoboGuice使用:(Your First Testcase)),今天我们来看下自己定义View的注入(Custom View). ...

  5. nutch搏斗之一

    nutch搏斗之一 问题描述: 在用nutch1.0做generate 包括5亿url的crawldb时,它默认按照64M分块,分成777个map task,在运行的后期出现 Could not fi ...

  6. hdu 折线切割平面 (java)

    问题: 仅仅要找到规律问题就攻克了,在做题时应该细致去发现数与数之间的联系. 折线切割平面 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit ...

  7. IOS程序设相关计开发技巧

    iOS programming architecture and design guidelines 原文地址:http://blog.mugunthkumar.com/articles/ios-pr ...

  8. 也说Javascript对象拷贝及疑问

    一.浅拷贝 当我们需要将一个对象拷贝至另一个对象时,我们一般会这么实现 function shadowCopy(source,target){ var target=target||{}; for(v ...

  9. Git在下搭建下环境的工具

    (本文稿来自:http://www.open-open.com/news/view/55387) Git是一个快速,可扩展的,分布式的版本控制系统.Git服务器起初是专为Linux开发,后来移植至Wi ...

  10. leetcode第一刷_Convert Sorted List to Binary Search Tree

    好,二叉搜索树粉末登场,有关他的问题有这么几个,给你一个n,如何求全部的n个节点的二叉搜索树个数?能不能把全部的这些二叉搜索树打印出来? 这道题倒不用考虑这么多,直接转即可了,我用的思想是分治,每次找 ...