一个异步编程的场景分析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/liusaint1992/article/details/79110245
一个常见场景,点击保存,获取表单数据,发送请求。
一种防重复点击的策略:点击按钮,出现遮罩,提交请求。。。能不能保证只提交一次请求呢?


未点保存时页面处理很卡没有响应的情况呢?
点了保存后的操作导致页面无响应时继续点保存呢?


在表单超复杂,用户的系统配置低的情况下,获取表单数据可能会花很长一段时间,甚至让浏览器停止响应,这时保存操作导致浏览器停止响应而我们又再次点击了保存按钮,会触发点击事件吗?会在什么时机执行。特别是我们的点击事件触发了一个异步的保存操作的情况下。


看下面的代码。
```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表示暂时不能点它。

猜你喜欢

转载自blog.csdn.net/liusaint1992/article/details/79110245