您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

遍历数组而不阻塞UI的最佳方法

遍历数组而不阻塞UI的最佳方法

您可以选择是否使用webWorkers:

对于需要与DOM或应用程序中的许多其他状态进行交互的代码,您不能使用webWorker,因此通常的解决方案是将工作分解为多个块,并在计时器上完成每个块的工作。计时器之间的块之间的中断使浏览器引擎可以处理其他正在进行的事件,不仅可以处理用户输入,还可以绘制屏幕。

通常,您可以负担每个计时器处理多个计时器的效率,这比每个计时器仅处理一个计时器效率更高,速度更快。此代码使UI线程有机会处理每个块之间的任何未决UI事件,这将使UI保持活动状态。

function processLargeArray(array) {
    // set this to whatever number of items you can process at once
    var chunk = 100;
    var index = 0;
    function doChunk() {
        var cnt = chunk;
        while (cnt-- && index < array.length) {
            // process array[index] here
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArray(veryLargeArray);

这是该概念的一个可行示例-不是相同的功能,而是一个使用相同setTimeout()思想通过多次迭代测试概率场景的长期运行过程:

您可以将上述内容制作成更通用的版本,.forEach()像这样的调用回调函数

// last two args are optional
function processLargeArrayAsync(array, fn, chunk, context) {
    context = context || window;
    chunk = chunk || 100;
    var index = 0;
    function doChunk() {
        var cnt = chunk;
        while (cnt-- && index < array.length) {
            // callback called with args (value, index, array)
            fn.call(context, array[index], index, array);
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArrayAsync(veryLargeArray, myCallback, 100);

除了可以一次猜测要分割多少块,还可以让经过的时间作为每个分割块的指导,并使其在给定的时间间隔内尽可能多地进行处理。不管迭代有多密集,cpu都会自动保证浏览器的响应能力。因此,您可以传递毫秒值(或仅使用智能认值),而不用传递块大小:

// last two args are optional
function processLargeArrayAsync(array, fn, maxTimePerChunk, context) {
    context = context || window;
    maxTimePerChunk = maxTimePerChunk || 200;
    var index = 0;

    function Now() {
        return new Date().getTime();
    }

    function doChunk() {
        var startTime = Now();
        while (index < array.length && (Now() - startTime) <= maxTimePerChunk) {
            // callback called with args (value, index, array)
            fn.call(context, array[index], index, array);
            ++index;
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        }
    }    
    doChunk();    
}

processLargeArrayAsync(veryLargeArray, myCallback);

如果循环中的代码不需要访问DOM,则可以将所有耗时的代码放入webWorker中。webWorker将独立于主浏览器Javascript运行,然后完成后,它可以通过postMessage返回任何结果。

WebWorker要求将将在WebWorker中运行的所有代码分离到一个单独的脚本文件中,但是它可以完全运行,而不必担心阻塞浏览器中其他事件的处理,也不必担心“无响应脚本”提示当在主线程上执行长时间运行的过程且不阻止UI中的事件处理时,可能会出现这种情况。

其他 2022/1/1 18:16:51 有560人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶