js异步ajax实现避免页面重复提交

简介: 同步基本是秉持着顺序执行的,为此在传送数据期间,浏览器一直处于等待状态,如果数据量过多或者网速过慢,就会出现假死情况(此内容在笔者此前博文<异步ajax实现顺序执行>中也有提出),所以当代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);
});

原文发布时间为:2018年04月13日
原文作者:社哥 

本文来源:开源中国 如需转载请联系原作者


目录
相关文章
|
15天前
|
JavaScript
JS代码动态打印404页面源码
源码由HTML+CSS+JS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面
14 0
JS代码动态打印404页面源码
|
15天前
|
测试技术 UED
断网之后的页面,Autox.js是点击还是上下滑动比较好?
断网之后的页面,Autox.js是点击还是上下滑动比较好?
|
15天前
|
测试技术 API Android开发
autox.js如何监听异常情况,比如网络中断、内存慢、应用死机或者页面无响应
autox.js如何监听异常情况,比如网络中断、内存慢、应用死机或者页面无响应
|
19天前
|
前端开发 JavaScript API
js【详解】ajax (含XMLHttpRequest、 同源策略、跨域、JSONP)
js【详解】ajax (含XMLHttpRequest、 同源策略、跨域、JSONP)
21 0
|
21天前
|
JavaScript API
前后端数据交互.js文件的axios的写法,想要往后端发送数据,页面注入API,await的意思是同步等待服务器数据,并返回,axios注入在其他页面,其他页面调用的时候,同步作用
前后端数据交互.js文件的axios的写法,想要往后端发送数据,页面注入API,await的意思是同步等待服务器数据,并返回,axios注入在其他页面,其他页面调用的时候,同步作用
|
23天前
|
移动开发 JavaScript
thinkPHP5.0开发微信H5页面分享接口signature验证失败,signature与微信 JS 接口签名校验工具返回结果不一致
thinkPHP5.0开发微信H5页面分享接口signature验证失败,signature与微信 JS 接口签名校验工具返回结果不一致
35 0
|
27天前
|
缓存 JavaScript 前端开发
老程序员分享:js刷新页面得重新加载和页面的刷新
老程序员分享:js刷新页面得重新加载和页面的刷新
16 0
|
前端开发 JavaScript 程序员
使用JavaScript将当前页面保存成PDF,支持图片和文字的保存
使用JavaScript将当前页面保存成PDF,支持图片和文字的保存
400 0
使用JavaScript将当前页面保存成PDF,支持图片和文字的保存
|
16天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
31 2