一个常见场景,点击保存,获取表单数据,发送请求。
一种防重复点击的策略:点击按钮,出现遮罩,提交请求。。。能不能保证只提交一次请求呢?
未点保存时页面处理很卡没有响应的情况呢?
点了保存后的操作导致页面无响应时继续点保存呢?
在表单超复杂,用户的系统配置低的情况下,获取表单数据可能会花很长一段时间,甚至让浏览器停止响应,这时保存操作导致浏览器停止响应而我们又再次点击了保存按钮,会触发点击事件吗?会在什么时机执行。特别是我们的点击事件触发了一个异步的保存操作的情况下。
看下面的代码。
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
//页面卡5s
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){
}
setTimeout(function(){
console.log('timeout');
},0)
}
```
快速连续点5次按钮。
输出顺序:
‘事件响应‘ 每5s输出一个
‘timeout‘ 瞬间输出5个
一开始以为是点击事件的优先级比setTimeout要高,所以先执行。
后来发现dom点击事件与setTimeout在event loop都是属于macrotask。
是我的5次点击结束之后才会执行到setTimeout,所以是5次点击事件加入消息队列的顺序先于setTimeout,所以先执行。没毛病。
当我们的浏览器因为代码执行时间过长停止响应的时候,依然是可以往事件队列中添加事件的。来自用户操作,来自网络等。
加入遮罩。用display:none。替代。
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
//页面卡5s
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){
}
btn.style.display = 'none';//隐藏
setTimeout(function(){
console.log('timeout');
},0)
}
```
输出:
事件响应 1次
timeout 1次
所以是可以实现只点击一次的效果的。
然而,在我们的项目中,出现了保存多次的情况。
观察发现,只是当开页面的那个瞬间狂点保存会出现保存多次的情况。同时我们的耗时操作是在异步操作中。分离场景如下:
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
setTimeout(function(){
//页面卡2s
var time = new Date().getTime();
while(new Date().getTime()-time < 2000){}
btn.style.display = 'none';//隐藏按钮
console.log('保存数据',new Date().getTime());
},0)
}
//加载完之后让页面卡5秒,在这5s中点击按钮。
window.onload = function(){
setTimeout(function(){
console.log('卡页面,请在卡页面的时候点三次保存')
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){}
console.log('卡页面结束');
},1000)
}
```
在点保存之前页面就很卡的时候,连续点3次按钮:
事件响应 X 3
保存数据 1517486862740
保存数据 1517486864742
保存数据 1517486866742
页面正常的情况下连续点3次保存按钮,输出 事件响应 1次 保存数据 1次
回到上面的问题,遮罩防点击的思路用的时候并不是那么靠谱。所以我们主要考虑页面本来很卡的时候我们再点了多次保存,这个时候遮罩无法阻挡我们保存多次。要用其他的防护措施。比如加个class表示暂时不能点它。
一种防重复点击的策略:点击按钮,出现遮罩,提交请求。。。能不能保证只提交一次请求呢?
未点保存时页面处理很卡没有响应的情况呢?
点了保存后的操作导致页面无响应时继续点保存呢?
在表单超复杂,用户的系统配置低的情况下,获取表单数据可能会花很长一段时间,甚至让浏览器停止响应,这时保存操作导致浏览器停止响应而我们又再次点击了保存按钮,会触发点击事件吗?会在什么时机执行。特别是我们的点击事件触发了一个异步的保存操作的情况下。
看下面的代码。
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
//页面卡5s
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){
}
setTimeout(function(){
console.log('timeout');
},0)
}
```
快速连续点5次按钮。
输出顺序:
‘事件响应‘ 每5s输出一个
‘timeout‘ 瞬间输出5个
一开始以为是点击事件的优先级比setTimeout要高,所以先执行。
后来发现dom点击事件与setTimeout在event loop都是属于macrotask。
是我的5次点击结束之后才会执行到setTimeout,所以是5次点击事件加入消息队列的顺序先于setTimeout,所以先执行。没毛病。
当我们的浏览器因为代码执行时间过长停止响应的时候,依然是可以往事件队列中添加事件的。来自用户操作,来自网络等。
加入遮罩。用display:none。替代。
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
//页面卡5s
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){
}
btn.style.display = 'none';//隐藏
setTimeout(function(){
console.log('timeout');
},0)
}
```
输出:
事件响应 1次
timeout 1次
所以是可以实现只点击一次的效果的。
然而,在我们的项目中,出现了保存多次的情况。
观察发现,只是当开页面的那个瞬间狂点保存会出现保存多次的情况。同时我们的耗时操作是在异步操作中。分离场景如下:
```JavaScript
var btn = document.querySelector('button');
btn.onclick = function(){
console.log('事件响应')
setTimeout(function(){
//页面卡2s
var time = new Date().getTime();
while(new Date().getTime()-time < 2000){}
btn.style.display = 'none';//隐藏按钮
console.log('保存数据',new Date().getTime());
},0)
}
//加载完之后让页面卡5秒,在这5s中点击按钮。
window.onload = function(){
setTimeout(function(){
console.log('卡页面,请在卡页面的时候点三次保存')
var time = new Date().getTime();
while(new Date().getTime()-time < 5000){}
console.log('卡页面结束');
},1000)
}
```
在点保存之前页面就很卡的时候,连续点3次按钮:
事件响应 X 3
保存数据 1517486862740
保存数据 1517486864742
保存数据 1517486866742
页面正常的情况下连续点3次保存按钮,输出 事件响应 1次 保存数据 1次
回到上面的问题,遮罩防点击的思路用的时候并不是那么靠谱。所以我们主要考虑页面本来很卡的时候我们再点了多次保存,这个时候遮罩无法阻挡我们保存多次。要用其他的防护措施。比如加个class表示暂时不能点它。