zoukankan      html  css  js  c++  java
  • 渲染大量数据我是这样操作的

    简介

    事情的由来是这样紫的,目前我负责公司内部的核心业务Gis天眼系统开发,遇到一个问题就是:后端返回几千条数据导致浏览器渲染失败,浏览器几乎是停滞状态。后来没有想到合适的解决方案,临时渲染少量数据解决了。我记得清清楚楚,我已经看过关于这样的问题怎么解决,可惜我没有使用,原因是学而不思,看而不用。后来由于家里有些事情,我请假回家休假休息了一段时间。回来之后开了一次会议,说我同事 实现了一个上述问题,用到了js线程。然后我就针对此问题开始了二次思考。就有了本文。

    JS线程

    浏览器内分js线程、GUI渲染线程、事件触发线程、等。大家都知道JS是单线程,但是问题来了,单线程如何实现异步,比如说我们经常使用的Ajax是怎么实现的呢?当你真正了解JS的Event Loop你就会明白!哦:原来如此。这里我就对线程进行抛砖引玉,如果想深入学习可以看一下这篇文章:https://segmentfault.com/a/1190000012806637

    如何渲染大量数据

    渲染大量数据肯定会涉及到GUI渲染线程与js线程。如下简单的代码:

    <!--
      dom 节点
    -->
    <div id="app">
                
    </div>    
    
    //js代码            
    var app=document.getElementById("app");   
    var Fragment=document.createDocumentFragment();
    for(var i=0;i<100;i++){ var span=document.createElement("span"); span.innerHTML = i; app.appendChild(span); }

    从上面代码可以分析、每次for循环使用dom进行渲染。浏览器是怎么渲染的呢?JS线程是单线程,它如果执行js线程,GUI渲染线程肯定会等候,这样一来渲染大量数据就会造成页面卡顿,甚至停滞、奔溃。页面显示效果就是一下子这些dom节点全部渲染出来。知道了这一点,我们就可以想办法解决它(渲染大量数据)。

    初探代码执行方式

    如下代码:

    console.log(1);
    setTimeout(function(){
        console.log(2);
    },100);
    console.log(3);

    大家肯定会说这个很简单,输出1 3 2。我想说的是大家看JS的Event Loop了吗?看了肯定知道其原理。

    1. 首先判断JS是同步还是异步,同步就进入主进程,异步就进入event table
    2. 异步任务在event table中注册函数,当满足触发条件后,被推入event queue
    3. 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主进程中。

    第一版本


    我使用了递归调用实现如下代码:
    var app=document.getElementById("app");
    
    var j=1;
    /**
     * 渲染方式
     * 
     * @number {number} 数量
     * */
    function showDom(number){
        console.log('渲染'+(j++)+"次");
        for(var i=0;i<number;i++){
            var span=document.createElement("span");
            span.innerHTML = i;
            app.appendChild(span);
        }
    }
    /**
     * 渲染大数据量的dom节点
     * 
     * @count {number} 总数量
     * 
     * */
    function init(count){
        if(typeof count!=="number") {
            console.warn(count+"类型不是:Number");
            return;
        }
        if(count>500){
            setTimeout(function(){
                showDom(500);
                init(count-500);
            },200);
        }else{
            showDom(count);
        }
    }
    
    init(4000);

    可以看出利用上述方式可以简单轻松实现渲染大量数据,给用户的感觉是,当前数据很多,我需要一步一步渲染。比之前一下子渲染几千条数据导致GUI渲染引擎卡顿、甚至停滞强多啦。

    第二版本

    接下来我又参考书籍使用了下面的代码。

    /**
     * 分时函数
     * @ary {Arry} 数据
     * @callback {Function} 回掉函数,一个参数,当前数据项
     * @count {Number} 数量
     * 
     * */
    function timeChunk(ary,callback,count){
        var objTs=Object.prototype.toString,//检测类型
        t;//定时器
        if(objTs.call(ary)!=="[object Array]"){
            return console.warn(ary+"---》应该是Arry类型");
        }
        if(objTs.call(callback)!=="[object Function]"){
            return console.warn(callback+"---》应该是回掉函数");
        }
        if(objTs.call(count)!=="[object Number]"){
            return console.warn(count+"---》应该是Number类型");
        }
        //开始执行函数    
        function start(){
            for(var i=0;i<Math.min(count||1,ary.length);i++){
                callback(ary.shift());
            }
        }
        return function(){
            t=setInterval(function(){
                if(ary.length===0){
                    return clearInterval(t);
                }
                start();
            },200);
        }
    }
    //后端返回数据
    
    var ayy=[];
    for (var a=0;a<50000;a++) {
        ayy.push(a);
    }
    //开始使用 分时函数
    var init=timeChunk(ayy,function(i){
        var span=document.createElement("span");
        span.innerHTML = i;
        app.appendChild(span);
    },500);
    //开始渲染大数据
    init();

    参考demo

    dome1 http://sandbox.runjs.cn/show/154bzaip

    dome2 http://sandbox.runjs.cn/show/hne29nn0

    总结

    要在学习中思考,在项目中实战。总有一天你会变得更加厉害!



  • 相关阅读:
    Does Spring Framework support Reactive @Transaction?
    How to explain the 'WebFlux' by analogy with 'Sports' ?
    Atom 插件推荐
    PC端页面适应不同的分辨率的方法 (转载)
    JS
    JS
    apicloud
    PHP
    CSS
    屏幕适配
  • 原文地址:https://www.cnblogs.com/xiaoxiaokun/p/8417743.html
Copyright © 2011-2022 走看看