概要
ajax通用封装代码的分析
- ajax实现
- ajax请求的缓存问题
- 异步编程模型
- 页面历史记录问题
编写ajax程序的基本过程:
- 创建XMLHttpRequest对象
- open,设置各类属性,method,async,url,url param data
- send,post data
- success,error,alwarys callback
- timeout callback
ajax().get('/users').success(function(data){
console.log(data);
});
通用ajax请求程序写法:
ajax(options) .before(callback(xhr)) .header(name,value) .headers({headers}) .get|post|other(url,[data],[contextType]) .success(callback(returnData,xhr),[jsonForceValidate=false]) .error(callback(statusCode,responseText,xhr)) .always(callback(statusCode,xhr)) .timeout(timeout,[callback(xhr)])
演示ajax请求的实现
演示ajax请求的实现:
Window.ajax = function (options){
var defaultOptions = {
async: true
};
options = extend(defaultOptions,options);
//核心功能
var _obj = {
xhr: createXhr(),successCallbacks:[],errorCallbacks:[],alwaysCallback:[],options:options
};
//前置处理方法
_obj.before = function(callback){
typeof(callback) === 'function' && callback(_obj.xhr);
return _obj;//为了支持链式操作,将原对象返回
};
//设置请求头
//header方法在get|post之前执行
_obj.header = function (name,value){
_obj.xhr.setRequestHeader(name,value);
return _obj;
};
//设置多个请求头
_obj.headers = function(headers){
if(object.prototype.toString.call(headers) === '[object Object'){
for(var name in headers){
_obj.xhr.setRequestHeader(name,headers[name]);
}
}
return _obj;
};
//成功的回调
_obj.success = function(callback,jsonForceValidate){
_obj.jsonForceValidate = jsonForceValidate;
if(typeof(callback) === 'function'){
_obj.successCallbacks.push(callback);
}
return _obj;
};
//失败error的回调
_obj.error = function(callback,jsonForceValidate){
_obj.jsonForceValidate = jsonForceValidate;
if(typeof(callback) === 'function'){
_obj.errorCallbacks.push(callback);
}
return _obj;
};
//超时的回调
_obj.timeout = function(timeout,callback){
_obj.xhr.timeout = timeout;
if(typeof(callback) === 'function'){
_obj.xhr.ontimeout= function(){
callback(_obj.xhr);
}
}
return _obj;
};
//get method发起ajax请求
// doAjax的操作
function doAjax(_obj,method,data,contentType){
var xhr = _obj.xhr;
data = encodeData(data,contentType);
if('get' === method){
url += (url.indexof('?') == -1 ? '?' : '&') + data;
}
//绑定事件处理器
bindEventHandler();
//open
xhr.open(method,_obj.options.async);
//send
if('post' === method && data){
xhr.setRequestHeader('content-Type',_obj.postContentType);
xhr.send(data);
}else{
xhr.send();
}
};
function encodeData(data,contentType){
if(object.prototype.toString.call(data) === '[object Object]'){
//json格式的处理
if('json' === contentType.toLowerCase()
&& typeof(JSON) === 'object'
&& typeof(JSON.stringify)=== 'function'){
_obj.postContentType = 'application/json';
return JSON.stringify(data);
} else{
//其他情况用urlencode处理
_obj.postContentType = 'application/x-www-form-urlencoded';
return encodeParam(data);
}
}
};
function bindEventHandler(){
};
function extend(obj1,obj2){
if(Object.prototype.toString.call(obj1) === '[object Object'
&& Object.prototype.toString.call(obj2) === '[object Object'){
for (var pname in obj2){
obj1[pname] = obj2[pname];
}
}
return obj1;
};
}
异步编程方法
异步编程方法
- 异步编程容易犯的错误:搞不清楚回调callback
- 多次请求仅仅允许最后一次有效
- 多个异步请求依次执行
- 多个异步请求同时执行
answer:
2.解决方法:请求放在全局变量中,第二次请求到来时,将第一次的全局变量abort(),后面的开始
3.
ajax().get('/req1',para).success(function(data){
ajax.get('/req2',data).success(function(data2){
ajax().get('/req3',data2).success(function(data3){
//biz use data3
});
});
});
- 并行处理,通过异步计数器完成
页面历史记录功能
页面历史记录功能
(点击浏览器“后退”可以重现数据)
实现此功能的要点:点击后退按钮 需要使url的地址改变,且要保证页面整体不可以刷新
技术:浏览器地址的锚点变化,可以实现url不刷新改变
需要添加window.onload
第二种实现方法:
html5中添加了一个方法是history.pushState
可以实现url的无刷新变化
function beforeLoad(e){
e && console.log(e.state);
var search = window.location.search;
if(search){
search = search.substr(search.lastIndexOf('=') + 1);
}
loadData(search);
btnState(search);
}
window.onload = window.onpopstate = beforeLoad;
function hit(keyword){
history.pushState({k:keyword},'new title','/cache.html?keyword=' + keyword);
beforeLoad();
}