Сколько нужно подразделить долго работающую функцию для отзывчивого интерфейса? - PullRequest
8 голосов
/ 11 ноября 2010

У меня довольно длительная (от 3 до 10 секунд) функция, которая загружает данные в фоновом режиме для довольно редко используемой части страницы.Вопрос, который у меня возникает, заключается в том, каково оптимальное время выполнения для выполнения и время задержки между тем, чтобы остальная часть страницы оставалась достаточно интерактивной, но загрузка данных не слишком задерживается из-за разбивки?

Например:

var i = 0;
var chunkSize = 10;
var timeout = 1;
var data; //some array

var bigFunction = function() {
    var nextStop = chunkSize + i; //find next stop
    if (nextStop > data.length) { nextStop = data.length }

    for (; i < nextStop; i++) {
       doSomethingWithData(data[i]);
    }
    if (i == data.length) { setTimeout(finalizingFunction, timeout); }
    else { setTimeout(bigFunction , timeoutLengthInMs); }     
};

bigFunction(); //start it all off

Теперь я провел некоторое тестирование, и chunkSize, который дает время выполнения около 100 мс, а 1 мс timeout, кажется, дает довольно отзывчивый интерфейс, но некоторые примерыЯ видел, рекомендую гораздо большие куски (~ 300 мс) и более длительные тайм-ауты (от 20 до 100 мс).Я упускаю некоторые опасности, разбивая свою функцию на слишком много маленьких кусочков, или метод проб и ошибок является безопасным способом определения этих чисел?

Ответы [ 2 ]

3 голосов
/ 17 ноября 2010

Любое значение тайм-аута меньше, чем примерно 15 мс, эквивалентно - браузер обновит DOM и т. Д., А затем выполнит тайм-аут.См. это и это для получения дополнительной информации.Я склонен использовать setTimeout(fn, 0).

Я бы проверял прошедшее время, а не угадывал числа, потому что, как указал Джейсон, между клиентами будут различия в скорости:

var data; // some array
var i = 0;
var MAX_ITERS = 20; // in case the system time gets set backwards, etc
var CHECK_TIME_EVERY_N_ITERS = 3; // so that we don't check elapsed time excessively
var TIMEOUT_EVERY_X_MS = 300;

var bigFunction = function () {
    var maxI = i + MAX_ITERS;
    if (maxI > data.length) { maxI = data.length }

    var nextTimeI;
    var startTime = (new Date()).getTime(); // ms since 1970
    var msElapsed;

    while (i < maxI) {
        nextTimeI = i + CHECK_TIME_EVERY_N_ITERS;
        if (nextTimeI > data.length) { nextTimeI = data.length }

        for (; i < nextTimeI; i++) {
            doSomethingWithData(data[i]);
        }

        msElapsed = (new Date()).getTime() - startTime;
        if (msElapsed > TIMEOUT_EVERY_X_MS) {
            break;
        }
    }

    if (i == data.length) {
        setTimeout(finalizingFunction, 0);
    } else {
        setTimeout(bigFunction , 0);
    }
};

bigFunction(); //start it all off
0 голосов
/ 11 ноября 2010

Тайм-аут 1 мс фактически не 1 мс.К тому времени, когда поток достигает 1 мс, он, вероятно, дает гораздо больше - потому что типичный временной интервал потока составляет 30 мс.В течение тайм-аута в 1 мс может выполняться любое количество других потоков, что может означать, что прошло 200 мс, прежде чем вы снова получили управление.

Почему бы просто не выполнить doSomethingWithData в совершенно другом потоке?

...