一道面试题:如何防止异步请求的重复提交

11月14日更新:前端

首先谢谢你们对这个问题的讨论,为了后来的童鞋方便浏览,我结合你们的论文,从新补充编辑此贴,为标蓝色加粗字体部分。面试

 

今天面试时考官问了一道题,如下是大体的回忆:ajax

 

问题大意: 若是点击一个按钮发送异步请求,如何防止短期内用户重复提交,从而形成数据覆盖等问题:后端

我回答的解决方法有:服务器

1. 提交后disable掉按钮,再次点击文本框时enable按钮网络

 (11月14号更新: dom

提交后disable按钮是经常使用方法,异步

外观表现上有:1. disable 按钮,在按钮上显示提交中等信息函数

                     2. 设置遮罩层,遮罩层上显示提交信息。字体

 

在代码处理逻辑上是:

                     第一步: 设置开关变量。

       第二步: 提交前关掉按钮

                     第三步: 在回调函数中打开按钮

                   

var isQuery = false;
function query() {
    if (!isQuery) {
        $.ajax({
            beforeSend: function() {
                isQuery = true
            },
            success: function() {
                isQuery = false
            },
            error: function() {
                isQuery = false;
                return;
            }
        })
    } else {
        alert("waiting!!!");
    }
}

 

 

 

如下一段文字仅是补充当时的场景,disable 按钮的方式看上面代码便可,如下可忽略  : )

上文中 ”再次点击文本框时enable 按钮使“ 不是disable 方法的一部分,只是为了补充 用开关变量disable按钮的思路可能存在一个问题:若是服务器端处理时间很长,甚至是服务器端挂掉了,一直在等超时的期间客户无法再次输入,所以设置了 再次点击文本框时enable 按钮 )

 

面试官追问,那么若是用户仍是快速地点击文本框,仍是能快速地提交,

 

2. 我想到了设置一个缓冲时间,例如200ms,200ms内的重复请求忽略,只执行最后一次的请求。

这个方法的代码:

var timer = null;
btn.addEventListener('click', function () {
    if (typeof timer === 'number') {
        clearTimeout(timer);
    }
    timer = setTimeout(function () {
        //添加提交按钮的事件处理
    }, 200);
}, false);

 

我说这会影响到全部的用户的每次请求都有延迟,而后继续想:

 

3. 因此想到提交后disable,而后settimeinterval,每隔必定时间,例如一秒钟,若是是disable的话那么enable 

( 其实这是在尝试解决上面提到的若是服务器端处理时间特别长,用户想从新输入的问题。

PS: 由于是面试,我这里是为复述整个故事,其余童鞋能够忽略这段 )

面试官指出,那么这个计时器就一直须要在运行咯,是啊,这样也是在消耗, (正在写博客的时候我在想可否设置一个计数器,若是连续好几回都是disable状态的话,能够移除定时器)

 

因而继续想:

4. 我想对每一个异步请求判断下IP,若是是短期内快速的重复提交,设定一个阈值,超过则判断为spam,把ip地址ban掉或者忽略请求,但这个缺陷是对每个请求都进行了额外操做。

而后面试官说这要后端配合,若是是前端呢?

5. 我想到了设置hash值,发异步请求时带上一个hash值,若是服务器端在处理上一个请求尚未完成时又来了新请求,那么能够丢弃,继续等待返回,这样不会覆盖数据。

而后发现,有走到须要后端配合了,面试官继续问,若是不要后端配合,若是仅仅是前端怎么作,

6. 我只好想到发送异步请求时候带上时间戳/hash值,返回数据的时候也带上时间戳/hash值,而后看是否是最近发送的那个请求,是则渲染,不然丢弃。

 

可是面试官在问有没有更好的方法,

我当时如实告诉面试官想不出来了,很抱歉,

 

刚才我看了下 xhr 对象的 API,发现有 abort() 方法,能当即取消请求,这个固然方便,每次保留上一次提交的xhr对象引用,下次点击时先abort() 上一个xhr请求,再从新发送请求,可是当时不知道这个方法,其实本身有想到是否是 xhr对象直接有取消请求的方法,但转而一想面试不可能这么简单吧,而后我不肯定这个方法是否存在。因此没回答这个方法。

(abort()  方法取消当前响应,关闭链接而且结束任何未决的网络活动。

这个方法把 XMLHttpRequest 对象重置为 readyState 为 0 的状态,而且取消全部未决的网络活动。例如,若是请求用了太长时间,并且响应再也不必要的时候,能够调用这个方法。请见: http://www.w3school.com.cn/xmldom/dom_http.asp

)

11月20日更新:感谢面试官,虽然面试挂了,还能有机会再次沟通,得知 abort()方法实际上是当时面试官内心期待的回答,那个滚动条优化,面试官期待的是 throttle函数,再次感谢。

 

固然不知道面试官但愿我能回答出来的更好方法是什么,因此请有看到的朋友能不吝赐教,谢谢。

相关文章
相关标签/搜索