遍历数组,而不阻塞UI的最佳方法 [英] Best way to iterate over an array without blocking the UI

查看:326
本文介绍了遍历数组,而不阻塞UI的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要遍历一些大型阵列,并将它们从API调用存储在骨干的集合。什么是做到这一点而不进行循环导致界面无响应的最佳方法是什么?

I am needing to iterate over some large arrays and store them in backbone collections from an API call. What is the best way to do this without making the loop cause the interface to become unresponsive?

Ajax请求的返回也块,返回的数据是如此之大。我想,我可以把它分解和使用的setTimeout,使其在更小的块异步运行,但有一个更简单的方法来做到这一点。

The return of the ajax request also blocks as the data returned is so large. I figure that I could split it up and use setTimeout to make it run asynchronously in smaller chunks but is there an easier way to do this.

我想到了一个网络工作者将是一件好事,但它需要改变保存在UI线程上的一些数据结构。我已经用这个来做Ajax调用尝试,但,当它返回数据到UI线程还有一段时间,当界面反应迟钝。

I thought a web worker would be good but it needs to alter some data structures saved on the UI thread. I have tried using this to do the ajax call but when it returns the data to the UI thread there is still a time when the interface is unresponsive.

在此先感谢

推荐答案

您打破阵列加工成块,并做到每块上的计时器。通常情况下,你有能力处理多个定时器每次上这是双方更有效,比只做每个定时器的速度更快。这code给出了UI线程有机会处理每块之间的任何未决的UI事件,这将保持用户界面激活。

You break the processing of the array into chunks and do each chunk on a timer. Usually, you can afford to process more than one on each timer which is both more efficient and faster than only doing one per timer. This code gives the UI thread a chance to process any pending UI events between each chunk which will keep the UI active.

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()的想法,以测试出的概率场景用不同的长期运行的进程很多迭代: http://jsfiddle.net/jfriend00/9hCVq/

Here's a working example of the concept - not this same function, but a different long running process that uses the same setTimeout() idea to test out a probability scenario with a lot of iterations: http://jsfiddle.net/jfriend00/9hCVq/

您可以到上述调用像一个回调函数更宽泛的版本 .forEach()确实是这样的:

You can make the above into a more generic version that calls a callback function like .forEach() does like this:

// 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密集型的迭代一定程度上自动确保浏览器的响应。因此,而不是传递一个块的大小,你可以通过在一个毫秒值(或者仅使用智能默认):


Rather than guessing how many to chunk at once, it's also possible to let elapsed time be the guide for each chunk and to let it process as many as it can in a given time interval. This somewhat automatically guarantees browser responsiveness regardless of how CPU intensive the iteration is. So, rather than passing in a chunk size, you can pass in a millisecond value (or just use an intelligent default):

// 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);

这篇关于遍历数组,而不阻塞UI的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆