Подтвердить что ты не робот

Почему некоторые разработчики JavaScript используют setTimeout в течение одной миллисекунды?

У меня проблема при использовании плагина jQuery tablesorter, и я не могу дважды вызвать триггер.

Например, это не сработает:

this._$table.trigger('update');
this._$table.trigger('sorton', [[[1,1]]]);

Но это работает:

this._$table.trigger('update');
setTimeout($.proxy(function() {
    this._$table.trigger('sorton', [[[1,1]]]);
}, this), 1);

А потом я вижу, что проблема была в триггере "обновление", он вызывает метод с телом:

function () {
    var me = this;
    setTimeout(function () {
        // rebuild parsers.
        me.config.parsers = buildParserCache(
        me, $headers);
        // rebuild the cache map
        cache = buildCache(me);
    }, 1);
}

Почему разработчик tablesorter использовал setTimeout с одной миллисекундой?

4b9b3361

Ответ 1

Это старый хак. Если событие должно быть запущено после другого события, вы можете использовать setTimeout с 1ms, чтобы убедиться, что событие запускается после другого события.

Ответ 2

Short annwer: очередь выполнения функций

Это короткий ответ на ваш вопрос. setTimeout с 0 или 1 миллисекундой используется для очередности выполнения функций. Читайте дальше, чтобы узнать, почему и как.

Javascript имеет однопоточное выполнение

Механизм Javascript - это однопоточный процесс. Поэтому всякий раз, когда разработчики хотели отложить выполнение некоторых функций, чтобы выполнить выполнение сразу после текущего, который только что был выполнен, setTimeout используется для фактического очереди следующей функции... У него нет что делать непосредственно с событиями, хотя функции могут быть обработчиками событий. Единственное событие в этом уравнении - это событие таймаута, созданное setTimeout.

Это пример двух функций, в которых первая функция во время выполнения выполняет очередную функцию, выполняемую сразу после нее.

function first()
{
    // does whatever it needs to

    // something else needs to be executed right afterwards
    setTimeout(second, 1);

    // do some final processing and exit
    return;
}

function second()
{
    // whatever needs to be done
}

Итак, для потока javascript очередь выполнения выглядит следующим образом:

first()
second()

Учтите, что это не связано со стеком вызовов функций.

Почему 1ms?

1ms - очень короткий промежуток времени, который (почти) гарантирует, что ваша вторая функция будет выполнена сразу после того, как ваша первая функция вернется. Иногда вы можете видеть даже 0ms, который фактически выполняет его сразу после того, как первая функция возвращает.

Если с другой стороны использовать более длительное время, то есть 100 мс, это может привести к тому, что другая функция будет выполняться в то же время и может оказать нежелательное влияние на весь процесс пользовательского интерфейса.

Зачем выполнять очередь в первую очередь?

Браузеры в настоящее время не позволяют функциям клиентской стороны размещать текущий сеанс браузера, наблюдая за длительными работами. Если определенная функция работает достаточно долго, механизм выполнения JavaScript Javascript приостанавливает ее и спрашивает у пользователя, хотят ли они ее завершить (убить) или дождаться завершения.

Это обычно нежелательный эффект, когда у вас действительно есть длительная работа. Например, представьте, что у вас есть функция, которая должна пройти через большое количество элементов, обрабатывающих каждый из них во время процесса. Вы определенно не хотите, чтобы пользователь завершил процесс, потому что цикл должен выполняться.

Что такое решение в этом случае? В таком случае вместо того, чтобы иметь одну функцию с циклом и выполнять ее, вы предпочтете функцию цикла (очереди), которая затем будет помещать вызовы функций для обработки каждого элемента. Это просто внешний скелет такой функциональности.

function queueItems(items) {
    for(var i = 0; i < items.length, i++)
    {
        setTimeout((function(item) {
            return function() {
                processItem(item);
            };
        })(items[i]), 0);
    }
}

function processItem(item) {
    // process individual item
}

Таким образом, вы не позволили бы функциям работать слишком долго и после того, как каждый управляемый элемент управления вернется к движку Javascript, сбросив его таймер зависания функции. Но имейте в виду, что пока ваши функции выполняются, ваш пользовательский интерфейс, скорее всего, будет невосприимчивым или самым непредсказуемым. Может быть, лучше поставить в очередь вашу функцию с некоторым промежутком времени между ними, поэтому пользовательский интерфейс будет реагировать, если это необходимо.

Ответ 3

Я думаю, что поскольку trigger('update') внутренне имеет setTimeout, только установив другой setTimeout, вы можете достичь желаемого порядка выполнения инструкции. Если вы не вызываете 'sorton' через setTimeout, он будет выполнен до 'update'.

С другой стороны, я полагаю, что 'update' использует setTimeout для предотвращения "обновления" как функции блокировки, когда может потребоваться много времени для выполнения.