zoukankan      html  css  js  c++  java
  • 【JS】利用闭包自制的沙漏类

    【需求】

    某应用有一耗时任务,目的是取出一批员工数据显示在页面上,但由于奇特的网络环境,每次调用都要数秒,客户要求在页面上动态显示耗时。

    【坑】

    动态显示耗时,多会用spanId,setInterval(funciton,mseconds),clearInterval(handler),startTime等一套五六个全局变量和函数。如果需要动态显示耗时的地方不止一处,那么区别和维护一堆全局变量和函数必是费力不讨好的事。

    【解决方案】

    必须用JS类实现,把要显示事件的SpanId,启动时间和句柄三个变量,启动、显示、停止三个动作都归纳到类里去。

    【后台耗时和取数的模拟实现】

    复制代码
    @RestController
    public class MockRestCtrl extends Pager{
        
        @RequestMapping(value="/fetchEmps", method=RequestMethod.GET)
        public Map<String,Object> fetchEmps(int waitSeconds){
            try {
                Thread.sleep(waitSeconds*1000);
            }catch(Exception ex) {
                //
            }
            
            Map<String,Object> retvalMap=new LinkedHashMap<String,Object>();
            List<Emp> datas=new ArrayList<Emp>();
            datas.add(new Emp(1,"Andy",24));
            datas.add(new Emp(3,"Bill",34));
            datas.add(new Emp(4,"Cindy",44));
            datas.add(new Emp(5,"Douglas",54));
            datas.add(new Emp(9,"Eliot",64));
            
            retvalMap.put("datas", datas);
            
            return retvalMap;
        }
    }
    复制代码

    上面代码使用了SpringBoot的RestController来实现后台,响应函数接受waitSecond参数,然后用Thread.sleep歇数秒,之后再造数据送回。

    有了这样的后台,前台送入不同的waitSeconds就能实现有差别的耗时。

    【沙漏类的实现】(本文重点)

    复制代码
    function Sandglass(){
        var spanId;
        var handler;
        var startTime;
    
        this.setSpanId=function(id){
            spanId=id;
        }
    
        this.start=function(time){
            startTime=time;
            clearInterval(handler);// 先调用一次,防止用户狂点导致多次调用setInterval        
            handler=setInterval(this.showElapsed,500);
        }
    
        this.showElapsed=function(){
            var now=new Date();
    
            var diff=(now-startTime)/1000;
            var d=parseInt(diff/86400);
            var h=parseInt(diff/3600)-24*d;
            var m=parseInt((diff % 3600) / 60);
            var s=parseInt(diff % 60);
            var elapsed=d+"day "+h+"hour "+m+"minute "+s+"second";
    
            document.getElementById(spanId).innerText=" 已耗时:"+elapsed;
        }
    
        this.stop=function(){
            clearInterval(handler);
        }
    }
    复制代码

    以上代码利用闭包实现了私有成员,这些成员只能被函数中定义的函数使用。下面我们可以看看对于使用者来说这个类该怎么用:

    【沙漏的初始化】

    var sandglass1=new Sandglass();
    sandglass1.setSpanId("span1");

    【沙漏的启动】

    sandglass1.start(new Date());

    【沙漏的停止】

    sandglass1.stop();

    从以上代码可以看出,使用者能用的方法少而简单,较难出错。Sandglass相对复杂的细节把控在了作者手中。

    【实现效果】

     【前台HTML代码】

    复制代码
    <table>
        <tr>
            <td width=50%>
                <table border="1" class="table">
                    <caption>Table1<span id="span1"></span></caption>
                    <thead>
                        <tr>
                            <td width="120px">id</td>
                            <td width="120px">Name</td>
                            <td width="120px">Age</td>
                        </tr>
                    </thead>
                    <tbody id="table1">
                    </tbody>
                </table>
            </td>
            <td width=50%>
                <table border="1" class="table">
                    <caption>Table2<span id="span2"></span></caption>
                    <thead>
                        <tr>
                            <td width="120px">id</td>
                            <td width="120px">Name</td>
                            <td width="120px">Age</td>
                        </tr>
                    </thead>
                    <tbody id="table2">
                    </tbody>
                </table>
            </td>
        </tr>
    </table>
    复制代码

    【前台JS代码】

    复制代码
    <script type="text/javascript">
        
        var sandglass1=new Sandglass();
        sandglass1.setSpanId("span1");
        
        var sandglass2=new Sandglass();
        sandglass2.setSpanId("span2");
        
        fillTable('table1',3,sandglass1);
        fillTable('table2',5,sandglass2);
    
        function fillTable(tableId,waitSeconds,sandglass){
            sandglass.start(new Date());
        
            $.ajax({
                url:"/mediacool/fetchEmps",
                data:{waitSeconds:waitSeconds},
                type:"get",
                dataType:"json",
                timeout:50000,
                error:function(xhr,textStatus,errorThrown){alert('ajax error')},
                success:function(rsps){
                    sandglass.stop();
                    showDatasInTable(rsps.datas,tableId);
                },
            });
        }
        
        function showDatasInTable(datas,tableId){
            
            var table=document.getElementById(tableId);
    
            // remove remained rows
            var trs=table.childNodes;
            for(var i=trs.length-1;i>=0;i--){
                table.removeChild(trs[i]);
            }
    
            // add new rows    
            for(var i=0,n=datas.length;i<n;i++){
                var data=datas[i];
                
                var td1=document.createElement("td");
                td1.appendChild(document.createTextNode(data.id));
                
                var td2=document.createElement("td");
                td2.appendChild(document.createTextNode(data.name));
                
                var td3=document.createElement("td");
                td3.appendChild(document.createTextNode(data.age));
    
                var tr=document.createElement("tr");
                tr.appendChild(td1);
                tr.appendChild(td2);
                tr.appendChild(td3);
                
                if(i % 2==0){
                    tr.style.backgroundColor="#f5f2eb";
                }
                
                table.appendChild(tr);
            }
        }
        
        function Sandglass(){
            var spanId;
            var handler;
            var startTime;
    
            this.setSpanId=function(id){
                spanId=id;
            }
    
            this.start=function(time){
                startTime=time;
                handler=setInterval(this.showElapsed,500);
            }
    
            this.showElapsed=function(){
                var now=new Date();
    
                var diff=(now-startTime)/1000;
                var d=parseInt(diff/86400);
                var h=parseInt(diff/3600)-24*d;
                var m=parseInt((diff % 3600) / 60);
                var s=parseInt(diff % 60);
                var elapsed=d+"day "+h+"hour "+m+"minute "+s+"second";
    
                document.getElementById(spanId).innerText=" 已耗时:"+elapsed;
            }
    
            this.stop=function(){
                clearInterval(handler);
            }
        }
    </script>
    复制代码

    END

  • 相关阅读:
    jquery 初篇
    python作用域和js作用域的比较
    javascript作用域
    第三篇、dom操作续
    dom事件
    第二篇 dom内容操作之value
    第三篇、变量
    第二篇、常量
    Node.js
    测试用例
  • 原文地址:https://www.cnblogs.com/heyang78/p/15729882.html
Copyright © 2011-2022 走看看