Во время циклов происходит сбой, но рекурсивная функция выдает ошибку превышения максимального стека вызовов - PullRequest
2 голосов
/ 11 июля 2019

Это простой вопрос, но я не смог найти никого, кто обращался бы к нему.

Использование chrome, запуск программы через localhost.Если у меня есть цикл while, который никогда не нарушает условия, он заставляет страницу зависать, никаких ошибок, и я даже не могу закрыть вкладку в Chrome.

Если у меня есть рекурсивная функция, которая вызывает себя бесконечно.Будет выдана максимальная ошибка стека вызовов.

Почему не существует отказоустойчивого цикла while?Как я могу избежать зависания страницы, когда цикл while работает бесконечно?(кроме правильной записи цикла while)

Ответы [ 4 ]

1 голос
/ 11 июля 2019

То, что вы называете отказоустойчивым, является отсутствующей функцией во всех реализациях, кроме Safari, в которой реализовано требование ES2016 JavaScript оптимизация хвостового вызова .В сафари вы не заметите никакой разницы между ними:

while (true) {
  // code
}

(function loop () {
   // code
   loop()
})();

Нет переполнения стека и, как и ожидалось, браузер зависает навсегда.Причина этого в том, что, если вы не используете рабочих, JS является однопоточным, и никакой другой код JS в очереди хода не выполняется.например.

setTimeout(function(){ alert("This will never happen!"); }, 0);
(function loop () {
   loop()
})();

Вы не должны писать во время циклов, которые не заканчиваются.Если вы допустили ошибку, я предлагаю вам сделать точку останова, чтобы проверить, почему она не завершается.В качестве альтернативы вы могли бы, если считаете, что что-то не так, сделать:

// TODO: remove debug limit
let limit = 100000; // limit
while (true)) {
    if(!limit--) {
        console.log('limit exceeded');
        break; // set breakpoint here in debugger
    }
}

Обратной стороной является то, что вам нужно удалить это, когда проблема будет решена.Моя IDE жалуется на этот TODO, поэтому он никогда не будет в git.Вы можете сделать то же самое с хвостовыми вызовами:

// TODO: remove debug limit
let limit = 100000; // limit
(function loop () {
      // code
      if(!limit--) {
          console.log('limit exceeded');
          return; // set breakpoint here in debugger
      }
      if (true) loop(); // might have another expression than true
})();
0 голосов
/ 11 июля 2019

Проблема остановки

Это приходит на ум, поскольку на самом деле может оказаться невозможным определить, будет ли цикл while детерминированно выполняться вечно.

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

Алан Тьюринг доказал в 1936 году, что общий алгоритм для решения проблема остановки для всех возможных пар ввода программы не может существовать.

https://en.wikipedia.org/wiki/Halting_problem

Решение Chrome

Вы можете нажать на три точки в правом верхнем углу и выбрать

Дополнительные инструменты> Диспетчер задач> Вкладка принудительного закрытия

0 голосов
/ 11 июля 2019

Почему нет надежного?

Вы отказоустойчивы.

Хотя верно, что компьютер не может обнаружить и перехватить все мыслимые бесконечные циклы или бесконечные рекурсии, существует множество примеров (вероятно, большинство примеров, которые вы бы практически написали), для которых компьютер мог бы на самом деле сделать это.

Но с какой целью?

Спецификации языка обычно не требуют этого. Реализации обычно не пытаются это сделать. Потому что им не нужно.

Вы проверяете свой код и обнаруживаете, что он не работает должным образом. Итак, вы исправите это.

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

Вы просто исправляете код.

кроме правильного написания цикла while

Да, это буквально решение.

0 голосов
/ 11 июля 2019

Ответ - использовать Chrome и оставить DevTools открытым.

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Причиной отсутствия мер защиты от бесконечных циклов, при которых создаются исключения для бесконечных циклов, является производительность.Соблюдайте разницу между проверкой и не проверкой.

(function(){"use strict";

var i=0, performance_now = performance.now.bind(performance);
var end = performance_now()+200;
while (performance_now() < end) i=i+1|0;

console.log('Ops/sec with checking: ' + Math.round(i / 200 * 1000));


var k = 0;
i = i<<7;
var startTime = performance_now();
while (k < i) void (k=k+1|0);
var endTime = performance_now();


console.log('Ops/sec -- unchecked:  ' + Math.round(i / (endTime - startTime) * 1000));

})();

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...