高阶函数应用:分时函数

什么是分时函数

将一个庞大的任务按照一定的时间段拆分成一个一个的小任务,以免任务太过庞一次执行所所造成的页面卡顿或假死。

举个例子:在页面中的树在网页中以树形结构显示分层数据,如果某一个列表有成百上千的数据,如果将每一个数据看成一个节点,在页面中渲染这个列表的时候,可能要一次性的网页面中创建成百上千个节点,

在短时间内往页面中大量添加 DOM 节点显然也会让浏览器吃不消,看到的结果往往就是浏览器的卡顿甚至假死。

const treeArr = [];
for (let i = 1; i <= 1000; i++) {
    treeArr.push(i); // 假设 treeArr 装载了 1000 个数据
}
renderTreeList(treeArr);
function renderTreeList(data) {
    for (let i = 0, l = data.length; i < l; i++) {
        let div = document.createElement('div');
        div.innerHTML = i;
        document.body.appendChild(div);
    }
};

这个问题的解决方案之一就是使用分时函数,分时函数是一种使用定时器分割循环的技术,为要处理的项目创建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。

在分时函数模式中,数组变量本质上就是一个"待办事宜"列表,它包含了要处理的项目。使用shift()方法可以获取队列中下一个要处理的项目,然后将其传递给某个函数。如果在队列中还有其他项目,则设置另一个定时器,并通过arguments.callee调用同一个匿名函数。

分时函数的重要性在于它可以将多个项目的处理在执行队列上分开,在每个项目处理之后,给予其他的浏览器处理机会运行,这样就可能避免长时间运行脚本的错误。一旦某个函数需要花 50 ms 以上的时间完成,那么最好看看能否将任务分割为一系列可以使用定时器的小任务。

如何使用分时函数

基于这个思想,我们先写一个demo,例如:

<body>
    <div id="myDiv"></div>
    <script>
        const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
        timeChunk(data, printValue);
        function printValue(item) {
            const div = document.getElementById('myDiv');
            div.innerHTML += `<p>${item}</p>`;
        }
        function timeChunk(array, process) {
            setTimeout(function () {
                // 取出下一个条目并处理
                const item = array.shift();
                // 将这个条目放入页面
                process(item)
                // 若还有条目,再设置另一个定时器
                if (array.length > 0) {
                    setTimeout(arguments.callee, 200);
                }
            }, 100);
        }
    </script>
</body>

这是将数组的每一项看成是每一个小任务,然后依次执行渲染。

下面我们再来看看一个详细的实现过程:

<body>
	<script>
        // 创建数据数组
        const ary = [];
        for (let i = 1; i <= 1000; i++) {
            ary.push(i);
        }
        // 利用这个时间函数把我们需要渲染的数据数组,添加节点的方法以及每次添加的个数
        const renderFriendList = timeChunk(ary, function (n) {
            const div = document.createElement('div');
            div.innerHTML = n;
            document.body.appendChild(div);
        }, 8);
        // renderFriendList中保存的是timeChunk返回出来的匿名函数引用
        renderFriendList();

        // 该分时函数接收 3 个参数:数据、创建节点逻辑的函数(可传入节点内容)、每一批创建的节点数量
        // 该分时函数将返回一个计时函数,根据数据是否已经创建完节点来决定是否停止
        function timeChunk(ary, fn, count) {
            //将数组的长度保存,提高性能
            let len = ary.length;
            const start = function () {
                // 创建规定数量的节点
                for (let i = 0; i < Math.min(count || 1, len); i++) {
                    //弹出传入数量的数据和数组长度中的最小值,
                    let item = ary.shift();
                    fn(item);
                }
            };
            return function () {
                let t = setInterval(function () {
                    // 如果全部节点都已经被创建好
                    if (len === 0) {
                        return clearInterval(t);
                    }
                    start();
                }, 200); // 分批执行的时间间隔,也可以用参数的形式传入
            };
        };
    </script>
</body>

本文章取自本人JS语言导师谢老师的学习总结,同时也感谢谢老师对我的谆谆教诲,感谢他带我走上前端这条道路,并让我为之不断向前

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值