Open VaJoy opened 8 years ago
var flag = 0;
$.smartAjax = function (args) {
var fn = arguments.callee;
$.ajax({
url: args.url,
data: { },
type: args.type,
dataType: "text",
beforeSend: function () {
flag += 1;
// 已请求过
if (flag > 1) {
if (args.smartType == 0) {
flag = 0;
//setTimeout(alert("aaa"), 10000); 这里的setTimeout无论这只多长时间都是立即执行。不知为什么。
(function () {
var i = 0;
var interval = setInterval(function () {
console.log(i);
i++;
if (i == 5) { clearInterval(interval); fn(args); };
}, 100);
})();
return false;
} else if (args.smartType == 1) {
alert("不能发请求。");
return false;
}
}
},
success: function (result) {
args.success(result);
flag = 0;
},
error: function () {
flag = 0;
}
});
};
只能算是最基本的实现,还有无限优化的空间。
为扩充提供无限可能,两个方案,两种实现方式。大家有优化点可以给出建议~!!
/**
* Created by 二狗 on 2015/12/10.
*/
var protectiveStrategy = {
timer : function() {
var url = [].pop.call(arguments),
ms = +([].pop.call(arguments)),
self = arguments.callee,
now = new Date().getTime();
ms = (typeof ms === 'number' && ms <= 2000) ? ms : 500;
if(!self.preTime || (now-self.preTime >= ms)) {
self.preTime = now;
$.ajax({
url : url,
//...
success : function() {
}
});
}
},
responsed : (function () {
var canSend = true,
url = [].pop.call(arguments);
return function() {
if(canSend) {
canSend = false;
$.ajax({
url : url,
//...
success : function() {
canSend = true;
}
});
}
}
}())
};
/**
*
* @param {String} plan 计划用何种方式代理,可选择的值为策略对象的key
* @param {String} url 请求的URL
*/
var ajaxProxy = function(plan ,url) {
var ary = plan.split(':'),
strategy = ary.shift();
ary.push(url);
protectiveStrategy[strategy].apply(null ,ary);
};
$.smartAjax = ajaxProxy;
function onClick() {
$.smartAjax('timer:1000' ,'localhost:8080');
//$.smartAjax('responsed' ,'localhost:8080');
}
不要有全局变量污染,尽量都写在smartAjax
方法里面为佳哦
//还差一步,就是$.smartAjax得到的方法不能在方法体内保存,要先用变量保存起来,智商不够
$.smartAjax = function(opts) {
var that = this,
proxyFn = function(type,options,context) {
var resFn;
if(type===0) {
resFn = (function(){
var _first = true,
startTime = +new Date();
return function(){
if(_first) {
_first = false;
$.ajax(options);
return;
}
var now = +new Date();
if(now - startTime < 500 ){
return;
}
startTime = now;
$.ajax(options);
}
})()
}else {
resFn = (function(){
var _completed = true,
completeFn = options.complete;
options.complete = function(){
completeFn&&completeFn();
console.log('完成');
_completed = true;
}
return function(){
if(_completed) {
_completed = false;
$.ajax(options);
}
}
})()
}
return resFn;
},
smartType = opts.smartType||0;
delete opts.smartType;
var resFn = proxyFn(smartType,opts);
return resFn;
}
//测试代码
//要先用after500保存下
var after500 = $.smartAjax({
smartType:0,
url:'http://localhost/test.php',
success:function(response){console.log(response)}
});
/*var complete = $.smartAjax({
smartType:1,
url:'http://localhost/test.php',
success:function(response){console.log(response)}
});*/
var a = 1;
var timer = setInterval(function(){
if(a==20) {
clearInterval(timer);
}
a++;
after500()
//complete();
},200)
@VaJoy 还差个return $.ajax(options); 你那样写就没法 $.smartAjax().done().error()xxx了 看到公司有人写的,改过来大概是这样,不过占用了beforeSend,不爽。
;(function() {
var limitPendingRequests = {};
$.ajaxSetup({
// 不缓存get
cache: false,
beforeSend: function(xhr, settings) {
// ajax 请求限制
var self = this;
var port = (function() {
var url = self.url;
var index = url.indexOf('_');
return index < 0 ? url : url.substring(0, index - 1)
}());
if (typeof settings.smartType === 'undefined') {
return true;
}
//500 毫秒下一次
if (settings.smartType === 0) {
if (limitPendingRequests[port]) {
return false;
}
limitPendingRequests[port] = true;
setTimeout(function() {
delete limitPendingRequests[port];
}, 500);
return true;
}
//请求完成进行下一次
if (settings.smartType === 1) {
if (limitPendingRequests[port]) {
return false;
}
limitPendingRequests[port] = true;
xhr.complete(function() {
delete limitPendingRequests[port];
});
return true;
}
return true;
}
});
})();
/*//
$.ajax({
smartType:0// 1,
xxxx
})*/
//这样做会触发ajaxError 事件,不过可以根据事件参数来判断是不是主动给取消了,参数有个值是canceled
@LittleBearBond 你貌似艾特错人了吧?我没提交过代码,如果要我写我会这么写:
$.smartAjax = (function () {
var _time_start = 0,
_flag = 1; //用于判断是否可以发送请求
return function (opt) {
var noop = function () {},
validFun = function (f) {
return typeof f === 'function' ? f : null
},
smartType = opt && opt.smartType,
processResponse = function (callback) {
['success', 'error'].forEach(function (resFunName) {
var resFun = validFun(opt[resFunName]) || noop;
opt[resFunName] = function () {
callback();
resFun.call(this, arguments)
}
});
},
typeCallback = {
0: function () {
_flag && (_time_start = Date.now());
if(_flag==0 && Date.now() - _time_start > 300) {
_flag = 1;
_time_start = Date.now()
}
},
1: function () {
if(_time_start) { //防止先调用smartType=0再调用smartType=1会失效
_flag = 1;
_time_start = 0
}
processResponse(function(){
_flag = 1;
})
}
};
var hasSmartType = typeCallback[smartType];
hasSmartType && typeCallback[smartType]();
if(_flag) {
hasSmartType && (_flag = 0);
return $.ajax(opt);
} else {
return $.Deferred()
}
}
})();
不存在外部变量,也不用占用什么beforeSend,也可以正常使用 $.smartAjax({...}).done(...)
<button id="req1">
请求 smartType:1
</button>
<button id="req2">
请求 smartType:2
</button>
/*
smartType:1 => 500ms 只能发送一次
smartType:2 => 等待请求返回后才能再次发起
*/
$.smartAjax = function(args) {
var send = function(opts) {
$.ajax(opts);
};
var afterSuccess = args.success;
var afterError = args.error;
return function() {
var exec = [
function() {
if (!send) return;
var oldSend = send;
send(args);
send = null;
setTimeout(function() {
send = oldSend;
}, 500);
},
function() {
if (!send) return;
var oldSend = send;
args.success = function(result) {
send = oldSend;
afterSuccess(result);
};
args.error = function(result) {
send = oldSend;
afterError(result);
};
send(args);
send = null;
}
];
exec[args.smartType - 1]();
};
};
var send1 = $.smartAjax({
smartType: 1,
url: 'http://sandbox.runjs.cn/show/teu1xt1n'
})
var send2 = $.smartAjax({
smartType: 2,
url: 'http://www.google.com',
success: function(data) {
//console.log(data);
console.log('data')
}
})
$('#req1').click(function() {
send1();
});
$('#req2').click(function() {
send2();
});
想破头了,依然没什么头绪。坐等最佳实践。
var queue = { //创建队列,点击按钮将请求添加到队列,然后按照固定时间释放
queStore : [],
length : 0,
timeout : 2000,
timer : null,
add : function(arg){
this.queStore.push(arg);
this.length++;
return this;
},
remove : function(i){
this.queStore.splice(i,1);
this.length--;
return this;
},
dequeue : function(){
if(queue.length>0){
var a = queue.queStore.shift();
queue.length--;
a();
}else{
clearInterval(this.timer);
}
},
fire : function(){
clearInterval(this.timer);
this.timer = window.setInterval(function(){queue.dequeue.call(queue);},this.timeout);
}
};
var flag = true;
$.smartAjax = function(arg){
var def = {
smartType:0,
url:"",
type:"POST",
success:null
};
var ajaxFun = function(){
$.ajax({
url:opation.url,
type:opation.type,
success:opation.success
});
};
var opation = $.extend(def,arg);
queue.add(ajaxFun);
switch(opation.smartType){
case 0 :
queue.fire();
break;
case 1 :
//另外一套逻辑。
break;
default:
throw new Error("参数类型错误!");
}
}
@qianduanMortal 其实不用搞队列,防抖的初衷本来就是忽略冗余的请求 没有什么最优解,只有参照的,可以参照我在上面发的代码
现在有一个按钮 $btn,我们给它绑定了点击事件,让它点一次就发一次POST请求去后端提交统计数据:
但是如果用户在很短的时间内点了好几下按钮(比如在1s里快速地点了5下),会向服务器发送很多条数据,这样并发量大的情况下服务器可能吃不消。 而且有时候我们也希望当前一条请求结束了(服务器返回数据了)之后才可以发起第二条请求。
所以请你封装一个叫
$.smartAjax
方法来做防抖处理,它可以有一个参数smartType
用于确定防抖方式——如果其值为 0 则要求在 500ms 内只允许发出一条请求; 如果参数smarType
值为 1 则表示只允许在前一条收到服务器响应(包括失败的响应)后才可以继续发送新请求。示例: