Использование setTimeout для обхода предупреждения сценария IE - PullRequest
4 голосов
/ 21 октября 2010

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

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

function factorial(x) {
    var buff = 1;

    for (i=x;i>=1;i--) {
        buff = buff * i;
    }

    return buff
}

Я пытался заменить код чем-то вроде этого, но он не работает должным образом:

function factorial(x) {
    if (x==0) {
        factbuff=1;
    }
    else {
        factbuff = x;
        factidx = x;
        setTimeout('dofact()',50);
    }
    return factbuff
}

function dofact() {
    if (factidx > 1) {
        factidx--;
        factbuff = factbuff * factidx;
    }
}

Кто-нибудь знает, что я делаю неправильно, и как я могу правильно реализовать функцию setTimeout для вычисления факториала, исключая предупреждение о скрипте в IE?

1 Ответ

0 голосов
/ 05 октября 2011

Это обновление и объяснение, почему код в предыдущем ответе (теперь удаленный) неправильный.

Сначала давайте повторим проблему: разрешаем выполнение факториальной функции в IE, не вызывая "длительный скрипт "предупреждение.

Это код, который был предложен ранее:

BROKEN. DO NOT USE. 

var executions = 0;
function factorial(x) {
    executions++;
    if (x > 1) {
    if (executions % 100 === 0) {
    return (function() {  // NO NO NO
        var y = x;
        setTimeout(function(y) { return y*factorial(y-1); }, 50);
    })();
    } else {
        return x*factorial(x-1);
    }
    } else {
    return 1;
    }
}

Хорошо, так что же с этим кодом?

  1. Факториальная функция сама является рекурсивной.Это означает, что функция вызывает себя.Каждый раз, когда функция вызывает себя, вы получаете другой кадр стека в памяти.То, что код выше пытается сделать, это назвать себя сто раз.Я не знаю, сколько вложенных стековых фреймов может выдержать браузер, но 100 кажется немного высоким.Я бы сделал это партиями по 10.

  2. Предложенная выше функция не является асинхронной.Когда вы используете setTimeout (), чтобы обойти предупреждение IE, функция должна стать асинхронной.Это означает - вместо того, чтобы вызывать его как var value = func(x);, вам нужно будет преобразовать свой код для передачи обратного вызова, который асинхронная функция вызывает, когда у нее есть результат.

  3. , связанный сПроблема выше, использование setTimeout в предложенном коде неправильно.В одном месте код делает это:

    return (function() {  // NO NO NO
        var y = x;
        setTimeout(function(y) { return y*factorial(y-1); }, 50);
    })();
    

Что это делает?Давайте разберемся с этим.У него есть анонимная функция.Эта функция вызывается (паренем open-close в конце).И значение этого вызова возвращается основной факториальной функцией.Какова ценность вызова анон функции?Проблема а: не возвращает значение.Это не определено.(См. Что возвращает функция javascript при отсутствии оператора return? )

Исправить это не так просто, как вернуть значение вызова в setTimeout().Это тоже неправильно. Возвращаемое значение setTimeout() - это идентификатор, который можно использовать для очистки тайм-аута с помощью clearTimeout(). Это определенно НЕ значение, доставляемое тем, что вызывает setTimeout.


ок, как это исправить?Во-первых, осознайте, что факториальная функция будет асинхронной, поэтому получение и отображение результата будет выглядеть так:

function displayFacResult(result) {
    var t2 = document.getElementById('t2');
    t2.value = result;
}

function b1_Click() {
    var t1 = document.getElementById('t1'),
        value = parseInt(t1.value, 10);
    computeFactorialAsynchronously(value, displayFacResult);
}

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

хорошо, теперь вычисление.

function computeFactorialAsynchronously(firstX, callback) {
    var batchSize = 3, limit=0, result = 1;
    var doOneFactorialStep = function(x, steps) {
        if (steps) { limit = x - steps; }
        if (x==1) { callback(result); }
        if (x>limit) {
            result *= x;
            doOneFactorialStep(x-1);
        }
        else {
            setTimeout(function () {
                doOneFactorialStep(x, batchSize);
            }, 1);
        }
    };
    doOneFactorialStep(firstX, batchSize);

    // the actual return value of the computation
    // always comes in the callback.
    return null;
}

Он вычисляет факториалы по «чанку», каждый чанк включает в себя N умножений и представлен переменной «шаги» в приведенном выше.Значение N (шагов) определяет уровень рекурсии.100, вероятно, слишком велик.3, вероятно, слишком мал для хорошей производительности, но это иллюстрирует асинхронность.

Внутри функции computeFactorialAsynchronously есть вспомогательная функция, которая вычисляет один фрагмент, а затем вызывает setTimeout для вычисления следующего фрагмента.Есть некоторая простая арифметика, чтобы управлять, когда прекратить вычислять текущий кусок.

рабочий пример: http://jsbin.com/episip

В некотором смысле переход к асинхронной модели уводит вас от чисто функциональной метафоры, где результат вычисления является результатом функции.Мы можем сделать это в javascript, но в нем появляется предупреждение IE "long running script".Чтобы избежать предупреждения, мы используем асинхронный режим, что означает, что возвращаемое значение «computeFactorial» не является фактическим факториалом.В асинхронной модели мы получаем результат через «побочный эффект» - от функции обратного вызова, которую функция вычисления вызывает, когда она завершает вычисления.

...