【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

原文地址:https://www.cnblogs.com/heyang78/p/15729882.html