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日
原文作者:社哥 

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


目录
相关文章
|
30天前
|
JavaScript 前端开发 容器
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
28 0
|
30天前
|
前端开发 JavaScript Java
使用Ajax进行异步交互:提升Java Web应用的用户体验
【4月更文挑战第3天】Ajax技术在Web开发中提升UX,通过与服务器异步交互实现页面局部更新,无需完整刷新。核心组件包括XMLHttpRequest、JavaScript、HTML/CSS及服务器端脚本。在Java Web应用中,可使用原生JavaScript或框架如jQuery、AngularJS实现Ajax请求。Ajax减少页面刷新,实现实时数据更新,即时表单验证和动态UI,显著改善用户体验,是现代Web开发不可或缺的一部分。
|
10天前
1.ajax同步和异步区别 2.post和get区别
1.ajax同步和异步区别 2.post和get区别
11 0
|
30天前
|
XML JSON 前端开发
学习Ajax使用异步对象发送请求
Ajax,全称Asynchronous JavaScript and XML(异步JavaScript和XML),是一种用于创建更好、更快以及交互性更强的Web应用程序的技术。
26 3
|
30天前
|
XML 前端开发 JavaScript
【JavaScript技术专栏】JavaScript网络请求与Ajax技术
【4月更文挑战第30天】Ajax是Web开发中实现动态数据更新的关键技术,允许不刷新页面即从服务器获取数据。它结合了HTML/CSS、DOM、XML/JSON和JavaScript。`XMLHttpRequest`是传统的Ajax实现方式,而`fetch` API是现代、简洁的替代选项。Ajax应用实例展示了如何使用fetch在搜索框输入时异步获取并显示结果,提升了用户体验。掌握这些技术对前端开发者至关重要。
|
30天前
|
JSON 前端开发 JavaScript
JavaScript原生实现AJAX技术详解
【4月更文挑战第22天】本文详细介绍了使用原生JavaScript实现AJAX技术,包括基本原理和步骤。AJAX借助`XMLHttpRequest`对象实现异步通信,允许网页在不刷新情况下与服务器交换数据。文中提供示例展示了如何创建请求、设置回调函数、处理响应数据以及设置请求头和发送不同类型的数据。此外,还讨论了跨域问题及其解决方案,如CORS和JSONP。掌握这些基础知识对前端开发者至关重要,尽管现代框架提供了更高级的抽象。
|
30天前
|
JavaScript 前端开发
node.js第四天--ajax在项目中的应用
node.js第四天--ajax在项目中的应用
31 0
|
30天前
|
XML 前端开发 JavaScript
node.js第三天-----ajax(3)
node.js第三天-----ajax(3)
27 0
|
30天前
|
JSON JavaScript 前端开发
node.js第三天-----ajax(2)
node.js第三天-----ajax(2)
25 0
|
30天前
|
XML 前端开发 JavaScript
jQuery中ajax如何使用
jQuery中ajax如何使用
29 0