js异步ajax实现避免页面重复提交
1 ajax概述
ajax同步与异步区别,在于:
同步基本是秉持着顺序执行的,为此在传送数据期间,浏览器一直处于等待状态,如果数据量过多或者网速过慢,就会出现假死情况(此内容在笔者此前博文<异步ajax实现顺序执行>中也有提出),所以当代ajax已经基本不再使用同步配置了;
异步则是发送后,接下来该干什么干什么,类似于行军途中,不断派出的斥候与正常军队行进之间的关系.只是有时候有些斥候的信息比较重要,在军队或下一个斥候派出前,必须得到这些斥候的信息,才好往下走.于此衍生了各种可能存在的问题,其中一个新人常遇到的问题就是:连续触发相同事件导致的重复提交.
2 问题描述
需要说明的是,重复提交对于不同情况有着不同的解决策略.
本文所述的方法,主要针对的是正常使用情况下,用户对于相同事件的误重复触发,譬如对于一个按钮,由于鼠标不好使或者新用户的不了解,连续点击两次以上.这种情况下,从页面js设计就可以解决;
与之正常使用情况对应的,即是异常情况,如某些用户恶意频繁发送请求,以获取一个网站的用户登录信息,这类问题就必然要和后台互动才能解决了,不在本文讨论范围内;
以下分情况讨论了可能出现的问题:
对于get请求,往往不会有什么太恶劣的影响,最多只是浪费下网络带宽,稍微增加服务器压力罢了,譬如查询两次相同的商品列表,仅是浪费时间;
对于post请求,重复触发很可能就产生用户不想要的某种后果,譬如点击通过积分购买商品,由于第一次网络较差导致反应时间较长,但用户以为自己第一次没有点击,于是再次点击,就相当于又发了一次post请求,最后的结果,就是买了两件相同的商品,这用户体验就很差了;
3 思路描述
ajax连续触发相同事件导致的重复提交,有一点可以利用的是:提交时的url必定相同.
所以只需将封装的ajax方法在发送请求之前,使用js变量存储该url,而在接收完相应数据后,再将该变量标记移除.
误操作导致要进行第二次ajax请求时,查询已有的js变量,如果变量标记存在,则说明第一次相应还没有回来,则直接禁止发送第二次相同的请求.
如此,即可避免ajax重复请求了.
4 封装代码
以下是封装ajax方法的代码(至少需要jQuery支持,如果有layer支持,则会使显示优化,客户体验更好):
/** * 参数说明: * 1.url(必填) * 2.config(选填,各种参数的配置) * 2.1.type:默认post * 2.2.async:默认true * 2.3.cache:默认false * 2.4.dataType:默认json * 2.5.contentType:默认utf8 * 2.6.data:默认无参数,此处一般需要使用者手动添加 * 2.7.packRemindType:默认:有layer插件时优先layer提示,否则为console提示.'console',控制台提示;'layer',layer提示;其他方式看需求增加,仅在函数值无效时有效 * 3.func_suc(选填):即ajax中的success * 4.func_error(选填):即ajax中的error * 5.func_comp(选填):即ajax中的complete * 其他说明 * 1.防止重复提交(自动启用,但在同步加载模式下看不出效果); * 2.提示模式,参考packRemindType; */function ajax_pack(url,config,func_suc,func_error,func_comp){ //1.request url repeat judge if(!window.lstAjaxUrl){ window.lstAjaxUrl={}; } if(window.lstAjaxUrl[url]){ console.log('ajax (url:%s) submit repeat!',url);//重复提示在控制台 return; }else{ window.lstAjaxUrl[url]=true; } //2.init necessary param config=config||{}; config.type=config.type||'post';//默认为type=get config.async=config.async||true;//默认为同步加载(选择此参数时,是没有必要用防重复提交功能的) config.cache=config.cache||false;//默认禁用缓存 config.dataType=config.dataType||'json'; config.contentType=config.contentType||'application/x-www-form-urlencoded; charset=utf-8'; config.data=config.data||{}; var packRemindTypeDefault=typeof(layer)==='undefined'?'console':'layer';//有layer时优先取layer config.packRemindType=config.packRemindType||packRemindTypeDefault;//默认:'console',控制台提示;'layer',layer提示;其他方式看需求增加,仅在函数值无效时有效 var func_send;//before send,not in param if(config.packRemindType==='console'){ func_send=function(){}; func_suc=func_suc||function(data){console.log(data);}; func_error=func_error||function(){console.log(url+' error');}; func_comp=func_comp||function(){}; }else if(config.packRemindType==='layer'){//需要layer支持 if(!window.lstLayerLoad){ window.lstLayerLoad={}; } func_send=function(){ window.lstLayerLoad[url]=layer.msg('加载中,请稍后...',{time:0});//layer.load(0, {shade: false,time:0}); //0代表加载的风格,支持0-2 }; var func_suc_init=func_suc||function(data){ if(data.success==1){ layer.msg(data.message,{icon:1}); }else{ layer.msg(data.message,{icon:2}); } }; func_suc=function(data){ layer.close(window.lstLayerLoad[url]); func_suc_init(data); }; var func_error_init=func_error||function(){ layer.msg('网络错误,请稍后重试!',{icon:2}); }; func_error=function(){ layer.close(window.lstLayerLoad[url]); func_error_init(); }; func_comp=func_comp||function(){}; }else{ console.log('nonsupport packRemindType.'); return; } //3.get param $.ajax({ url:url, type:config.type, async:config.async, cache:config.cache, dataType:config.dataType, contentType:config.contentType, data:config.data, beforeSend:function(){ func_send(); }, success:function(data){ if(!window.lstAjaxResult){ window.lstAjaxResult={}; } window.lstAjaxResult[url]=data;//封装结果 func_suc(data); }, error:function(){ func_error(); }, complete:function(data){ /* var mResult; if(config.dataType==='json'){ mResult=JSON.parse(data.responseText); }else{ mResult=data.responseText; } */ func_comp(); window.lstAjaxUrl[url]=false;//释放url锁 } }); }
以上封装代码中的很多默认值是根据笔者公司的倾向确定的,使用者也可根据自己需要予以修改(只要是这个思路就可以). 以下为使用该封装函数的代码,其中url为假象url,就不用真实url替代了.
//某个vue methods中方法内容var this=that;ajax_pack(mGlobalUrl.loadOne,{ type:'get', data:{ strFormCode:strFormCode }},function(data){ that.mainData=Object.assign(that.mainData,data); });
作者:社哥
来源:https://my.oschina.net/yangyishe/blog/1795196
共同学习,写下你的评论
评论加载中...
作者其他优质文章