在开发中一定有这种情况:
一个简易的需求,点一个按钮,则向服务器请求资源,不作处理时,多次点击后会有很多个请求在等待。
最粗暴的解决方式是点一次就将按钮disable掉,比如
$("input[type=submit]").attr('disabled',false)
但这种形式缺点也很多,还有稍微优雅一点的方式完全由JS来控制,就是使用一个变量来保存状态:
var post_flag = false; function post(){ //如果正在提交则直接返回,停止执行 if(post_flag) return; //标记当前状态为正在提交状态 post_flag = true; $.ajax({//进入AJAX提交过程 url:'/post.php', data:{a:1,b,1} }) .done(function () { // something }) .always(function () { post_flag = false; }) }
但无论如何每个请求都需要写这样一段重复性的代码,又臭又长,还和业务逻辑混在一起,也不是最佳的解决方案。
那怎么才能把这个近似的业务逻辑封装起来呢?这里就用到了jquery ajax的预处理功能(一般其他的ajax工具也都有预处理函数)
这里只针对jquery:
!function () { /*设置ajax全局默认值*/ $.ajaxSetup({ async: true, cache: false, dataType: 'json' }); /*ajax预处理缓存*/ var ajaxRequestList = {}; /* 判断唯一标识,同一个ajax只能同时存在一次 single(string): 唯一标识 mine(boolean): 如果ajax标识重复则用自身(true)还是原来的 once(boolean): 是否唯一,唯一(true)则只会请求成功一次 */ $.ajaxPrefilter(function(options, originalOptions, jqXHR) { if (typeof originalOptions.single === 'string') { if (!ajaxRequestList[originalOptions.single]) { ajaxRequestList[originalOptions.single] = jqXHR; if (originalOptions.once === true) { jqXHR.fail(function() { delete ajaxRequestList[originalOptions.single]; }); } else { jqXHR.always(function() { delete ajaxRequestList[originalOptions.single]; }); } } else { if (originalOptions.mine === true) { ajaxRequestList[originalOptions.single].abort(); } else { jqXHR.abort(); } } } }); }();
基本思路就是利用预处理器ajaxPrefilter将请求信息储存在一个对象中,可以通过传入的额外标志来控制重复提交
$.ajax({ url: 'post.php', type: 'POST', data: {id: 0}, single: 'post_1' // 唯一标识 当有这个标识存在,预处理器会拦截本次请求 }) .done(function (data) { // something });
$.ajax({ url: 'post.php', type: 'POST', data: {id: 0}, single: 'post_2', mine: true // 当single重复时用自身并放弃之前的ajax请求 }) .done(function (data) { // something });
$.ajax({ url: 'post.php', type: 'POST', data: {id: 0}, single: 'post_3', once: true // 只允许请求成功一次,一旦成功,这个single永远不会在发起请求 }) .done(function (data) { // something });通过预拦截器和这三个标识,可以很方便的应对基本所有情况,在项目中也没用发现任何问题