你是否发现项目中有很多页面只用到了框架不到十分之一的内容,还引了压缩后还有70多kb的jquery库
你是否发现项目中就用了两三个underscore提供的方法,其他大部分的你方法你甚至从来没有看过
你是否发现fetch好像比ajax好用那么一点
你是否想过自己封装个ajax....
 
纯前端写得久了,便想折腾点事情。比如先定一个小目标,年前自己写个类jquery轻量级库....
 
那么就从自己封装一个ajax切入吧,首先我整理的一个思维导图,一目了然

解析参数数据

通常我们的请求后面会有一些参数,如果是get请求当然可以直接通过'&'拼在url后面。那么post就需要做一下处理了,如果参数是字符串,则将字符串用‘&’符号切割转化成键值对形式,同时用encodeURIComponent转码,最后类似于jquery的处理,将/%20/g(空格)替换成'+'。
      getData: function(){
var name, value;
if (opts.data) {
if (typeof opts.data === "string") {
opts.data = opts.data.split("&");
for (var i = 0, len = opts.data.length; i < len; i++) {
name = opts.data[i].split("=")[0];
value = opts.data[i].split("=")[1];
opts.data[i] = encodeURIComponent(name) + "=" + encodeURIComponent(value);
}
opts.data = opts.data.replace("/%20/g", "+");
} else if (typeof opts.data === "object") {
var arr = [];
for (var name in opts.data) {
var value = opts.data[name].toString();
name = encodeURIComponent(name);
value = encodeURIComponent(value);
arr.push(name + "=" + value);
}
opts.data = arr.join("&").replace("/%20/g", "+");
} //使用GET方法或JSONP,则手动添加到URL中
if (opts.type === "GET" || opts.dataType === "jsonp") {
opts.url += opts.url.indexOf("?") > -1 ? opts.data : "?" + opts.data;
}
}
},

创建jsonp

如果dataType为jsonp的话,其实我们就可以理解为不是ajax请求了,而是伪造了一个script标签,通过script的src属性相当于发起了一个请求,其中带了一个callback(这里是名称叫jsonp_timeName)的参数,最终约定好后台的数据包通过jsonp_name(data)这种形式包裹起来,这样就相当于前端再回调了一个jsonp_name的方法,将数据通过参数的形式带过来了,所以前端js需要实现一个名叫jsonp_name的方法。其实jsonp跨域的方法有很多种,比如还有伪造iframe等,跨域详情解决方案可以参考我的博文 http://www.cnblogs.com/liliangel/p/5760426.html
 
      createJsonp: function(){
var script = document.createElement("script"),
timeName = new Date().getTime() + Math.round(Math.random() * 1000),
callback = "jsonp_" + name; window[callback] = function(data) {
clearTimeout(ajax.options.timeoutFlag);
document.body.removeChild(script);
try {
data && (data = JSON.parse(data));
} catch (e) {
console.error('ajax error for json parse responseText');
}
ajax.success(data);
}
script.src = url + (url.indexOf("?") > -1 ? "" : "?") + "callback=" + callback;
script.type = "text/javascript";
document.body.appendChild(script);
ajax.timeout(callback, script);
},

创建XHR

首先通过兼容性处理的getXHR()方法得到xhr对象,接着设置请求头,区分post、get。每当 readyState 改变时,就会触发 onreadystatechange 事件,readyState 属性存有 XMLHttpRequest 的状态信息。这里我相当于重写readystate事件监听,来做我自己的相应逻辑处理,由于执行abort()方法后,有可能触发onreadystatechange事件,所以设置一个ajax.options.timeoutBool标识,来忽略中止触发的事件。最后调用xhr的send()方法发送出请求,同时渲染timeout()方法。
    createXHR: function(){
//创建对象
xhr = ajax.getXHR();
xhr.open(opts.type, opts.url, opts.async);
//设置请求头
if (opts.type === "POST" && !opts.contentType) {
//若是post提交,则设置content-Type 为application/x-www-four-urlencoded
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
} else if (opts.contentType) {
xhr.setRequestHeader("Content-Type", opts.contentType);
}
//添加监听
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (opts.timeout !== undefined) {
//由于执行abort()方法后,有可能触发onreadystatechange事件,所以设置一个ajax.options.timeoutBool标识,来忽略中止触发的事件。
if (ajax.options.timeoutBool) {
return;
}
clearTimeout(ajax.options.timeoutFlag);
}
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
var responseText = xhr.responseText;
try {
xhr.responseText && (responseText = JSON.parse(responseText));
opts.success(responseText);
} catch (e) {
console.error('ajax error for json parse responseText');
//opts.error(xhr);
}
} else {
opts.error(xhr);
}
}
};
//发送请求
xhr.send(opts.type === "GET" ? null : opts.data);
ajax.timeout(); //请求超时
}

兼容IE6

获取xhr对象可能会存在低版本ie兼容性问题,为此这样判断处理一下
      getXHR: function(){
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
//遍历IE中不同版本的ActiveX对象
var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];
for (var i = 0; i < versions.length; i++) {
try {
var version = versions[i] + ".XMLHTTP";
return new ActiveXObject(version);
} catch (e) {
console.log('error ajax',e)
}
}
}
}

设置请求超时

前面我定义了一个全局的属性timeoutFlag,这里通过settimeout延时函数给它赋值。如果是jsonp,则移除原来追加的script标签,否则通过全局的xhr条用abort()方法终止正在发送的请求!

    timeout: function(callback, script){
if (opts.timeout !== undefined) {
ajax.options.timeoutFlag = setTimeout(function() {
if (opts.dataType === "jsonp") {
delete window[callback];
document.body.removeChild(script);
} else {
ajax.options.timeoutBool = true;
xhr && xhr.abort();
}
}, opts.timeout);
}
},

全局变量

var defaultOpts = {
url: '', //ajax 请求地址
type : 'GET', //请求的方法,默认为GET
data : null, //请求的数据
contentType : '',//请求头
dataType : 'json', //请求的类型,默认为json
async : true, //是否异步,默认为true
timeout: 5000, //超时时间,默认5秒钟
before : function() {
console.log('before')
}, //发送之前执行的函数
error: function() {
console.log('error')
}, //错误执行的函数
success: function() {
console.log('success')
} //请求成功的回调函数
} for (i in defaultOpts) {
if (opts[i] === undefined) {
opts[i] = defaultOpts[i];
}
}
    var xhr = null;     options: {
timeoutFlag: null, //超时标识
timeoutBool: false //是否请求超时
},

初始化调用

我这里是用面向对象函数方式写的,核心初始化代码如下:
init: function(){
opts.before();
ajax.getData();
opts.dataType === "jsonp" ? ajax.createJsonp() : ajax.createXHR();
},     ajax.init();

设置AMD等规范

如果是用requireJS这种方法引用,那么还需要设置一下amd、cmd或者commonJs规范
// AMD && CMD
if(typeof define === 'function'){
define(function(){
return li;
});
// CommonJS
}else if(typeof module !== "undefined" && module !== null){
module.exports = li;
// window
}else{
window.li = li;
}

调用示例

调用示例,我这里只贴出异步的方式,当然还有好几种情况,比如出错等,这里不一一展示
 
默认为gety异步请求,超时时间5秒钟。before为请求前执行的函数,通常我们可以写统一的loading动画。当发生405/500等这种错误时,会调用error方法,当然我们通常在success回调函数里做逻辑处理。这里尽量跟jquery库的ajax封装保持一致,是为了更符合原有的开发编码习惯
 

结果

控制台输出如下:

我这里用$这个符合作为全局对象引入,也是为了更符合原来用jquery的编码习惯,但是这里只实现了其中的ajax方法哦,其他项目中高频出现的方法,以及常用的小组件后续慢慢补充....
 
ITer,请跟随兴趣一路前行,个人站点www.liliangel.cn,欢迎指导交流

自己封装个ajax的更多相关文章

  1. 先定一个小目标,自己封装个ajax

    你是否发现项目中有很多页面只用到了框架不到十分之一的内容,还引了压缩后还有70多kb的jquery库 你是否发现项目中就用了两三个underscore提供的方法,其他大部分的你方法你甚至从来没有看过 ...

  2. 封装的ajax请求

    在做登录注册这类提交表单数据时,我们经常需要局部刷新网页来验证用户输入的信息,这就需要用到ajax请求,我们通常需要获取表单中的数据,发起ajax请求,通过服务程序,与数据库的数据进行比对,判断信息的 ...

  3. 封装一个Ajax工具函数

    /*封装一个ajax工具函数*/ window.$ = {}; /*通过$定义一个ajax函数*/ /* * 1. type   string   请求的方式  默认是get * 2. url     ...

  4. 原生封装的ajax

    原生封装的ajax的代码如下: //将数据转换成 a=1&b=2格式; function json2url(json){ var arr = []; //加随机数防止缓存; json.t = ...

  5. 原生ajax与封装的ajax使用方法

    当我们不会写后端接口来测试ajax时,我们可以使用node环境创建一个本地服务器. 1.创建一个本地服务器可参考http://www.cnblogs.com/heyujun-/p/6793900.ht ...

  6. 自己封装的AJAX (带JSON)

    最简单的封装的AJAX: function myajax(url,onsuccess,fail){ //确定是否支持xhr var xhr = new XMLHttpRequest ? new XML ...

  7. mui封装的ajax请求

    由于项目中引进MUI框架,所以就不需要引进jquery,但需要和后台交互时,常写为jquery格式:所以笔者觉得有必要将mui封装的ajax请求在这里提一下: 1,mui框架基于htm5plus的XM ...

  8. jQuery 封装的ajax

    jquery封装的ajax 具体操作: $.get(url  [,data]  [,fn回调函数]   [, dataType]); data:给服务器传递的数据,请求字符串 .json对象 都可以设 ...

  9. Jquery封装的ajax的使用过程发生的问题

    Jquery封装的ajax的使用过程发生的问题 今天在做项目的时候使用到了ajax来完成项目前后端数据交互,在之后发现在前端没有数据显示,而后端数据确实存在,在多次检查代码之后,发现代码并不存在问题, ...

随机推荐

  1. Android LayoutInflater原理分析,带你一步步深入了解View(一)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲Vi ...

  2. BZOJ4350: 括号序列再战猪猪侠

    Description 括号序列与猪猪侠又大战了起来. 众所周知,括号序列是一个只有(和)组成的序列,我们称一个括号 序列S合法,当且仅当: 1.( )是一个合法的括号序列. 2.若A是合法的括号序列 ...

  3. 高性能 CSS3 动画

    注:本文出自腾讯AlloyTeam的元彦,文章也可以在github上浏览.请尊重版权,转载请注明来源,多谢-- 高性能移动Web相较PC的场景需要考虑的因素也相对更多更复杂,我们总结为以下几点: 流量 ...

  4. JS-sort排序

    var arr = [ 'c', 'd', 'a', 'e' ];// arr.sort();// alert( arr );var arr2 = [ 4,3,5,5,76,2,0,8 ];// ar ...

  5. Windows和linux的文件共享(1)

    今天是我学习linux以来第一次写博客.带着一种激动心情我开始尝试着去完成第一篇博客.从易到难.所以第一次我就主要学习了Windows之间的文件共享. Window之间的文件共享是通过局域网实现的.局 ...

  6. hadoop搭建初步总结

    1.安装JDK1.1上传运用软件FileZilla,将windows上的jdk压缩包放到linux的root目录下 1.2解压jdk #创建文件夹 mkdir /usr/java(不要挂在在" ...

  7. Win7下硬盘安装Linux双系统

    Win7下硬盘安装CentOS6.2 一.准备工作:划出磁盘空闲空间和准备安装文件  参考文献: [Win7下硬盘安装Linux总结(CentOS)]来源:Linux社区  作者:lixianlin ...

  8. React Native填坑之旅--重新认识RN

    如同黑夜里的一道光一样,就这么知道了F8. F8是每年一次Facebook每年一次的开发者大会.每次大会都会release相应的APP,iOS.Android都有.之前都是用Native开发的,但是2 ...

  9. Xenu Link Sleuth-简单使用

    1.工具说明 xenu link sleuth,主要用于测试网站死链接.包括图片.链接. 下载地址:http://home.snafu.de/tilman/xenulink.html#Download ...

  10. Reactnative 随笔一

    ---恢复内容开始--- 1.ReactDOM.render()    React的最基本方法,用于将模板转为HTML语言,并插入指定的DOM节点 将h标签插入example节点 2.HTML语言直接 ...