Значение глобальной переменной загадочным образом сбрасывается после превышения стека бесконечной рекурсией в node.js - PullRequest
1 голос
/ 28 июля 2011

Я хотел посчитать шаги бесконечной рекурсивной функции в node.js (v0.4.10), используя глобальное увеличение значения. однако счет всегда претендует на ноль

> c = 0
> (function f() { c++; console.log(c); f() })();
1
2
...
18648
RangeError: Maximum call stack size exceeded
> c 
0

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

используется global.c

это правильное поведение? что здесь происходит? например в хроме (v14) c содержит окончательный результат, как и ожидалось.

UPDATE

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

c = 0;
try {
  (function f() { c++; f() })();
} catch(e) {};
console.log(c);

однако, между интерактивным node.js и консолью javascript chromium все еще существует разница, где значение сохраняется в необработанном исключении

1 Ответ

2 голосов
/ 28 августа 2011

Каждый интерактивный режим ведет себя немного по-другому, чем стандартное исполнение файла JavaScript (Исаак Шлютер где-то писал: " Я никогда не видел REPL, в котором не было добавлено хоть немного магии").Интерактивный режим должен оценивать текст, который обычно запускает код в другом контексте.

В случае Node.JS каждая команда выполняется в своем собственном контексте, тогда REPL позаботится, чтобы мы вернулись с результатами,Если мы не выполняем команду из-за некоторых ошибок, значения наших переменных остаются неизменными (поскольку измененные переменные «умирают» в контексте выполнения).Когда мы запускаем файл JavaScript стандартным способом, у нас нет этого отдельного контекста выполнения, и мы напрямую меняем наши переменные.

Вы можете изменить свой пример, чтобы вручную создать ошибку и воспроизвести ее:

c=0;
(function f(x){ c++; if(x) f(x-1); else throw new Error();  })(10);

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

...