JavaScript: pila de llamadas y la magia de su tamaño

¡Hola, Khabrovites!





La mayoría de los desarrolladores que han utilizado la recursividad para resolver sus problemas han visto este error:





 RangeError: Maximum call stack size exceeded. 
      
      



Pero no todos los desarrolladores pensaron en lo que significa "tamaño de pila de llamadas" y en qué tamaño es. ¿Y cómo medirlo?





Creo que aquellos que trabajan con lenguajes que trabajan directamente con la memoria pueden responder fácilmente a esta pregunta, pero lo más probable es que un desarrollador front-end típico se haga estas preguntas por primera vez. Bueno, ¡intentemos resolverlo!





Mucha gente cree que el navegador nos limita precisamente en el número de llamadas, pero no es así. En este artículo, le mostraré con ejemplos simples cómo funciona realmente.





¿De qué estás hablando, autor?

Para el artículo, es importante comprender conceptos como Pila de ejecución, Contexto de ejecución. Si no sabe qué es, le aconsejo que lo lea. Este recurso ya tiene suficientes artículos buenos sobre este tema. Ejemplo:  https://habr.com/ru/company/ruvds/blog/422089/





¿Cuándo ocurre este error?

Tomemos un ejemplo simple: una función que se llama a sí misma de forma recursiva.





const func = () => {
    func();
}
      
      



Si intentamos llamar a una función de este tipo, veremos el error en la consola / terminal, que mencioné anteriormente.





Pero, ¿qué pasa si observa cuántas veces se ejecutó la función antes de que ocurriera el error?





Chrome DevTools 2021. . .





:





let i = 0;

const func = () => {
  i++;

  func();
};

try {
  func();
} catch (e) {
  //          
  console.log(i);
}
      
      



13914. , , , 14 .





, . , :





let i = 0;

const func = () => {
  let someVariable = i + 1;
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}
      
      



, , someVariable



  . , , . 12523 . , . , , , .





? ? , , ?!





- . . , , - . -, , , ? , ? : 





let i = 0;

const func = () => {
  let a = i + 1;
  let b = a + 1;
  let c = b + 1;
  let d = c + 1;
  let e = d + 1;
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}
      
      



, . , - 8945. , . , . , .





Execution Stack (Call Stack) - . . , . , , . . , , .





. -   . - , . Call Stack (Execution Stack), , Execution Context - ( this). , , "" , , . Execution Context, , . "" , .





. , ? , , Chrome?





-

, , (, ). Execution Stack, . N, K. X.





- , ( ) :





FunctionSize = N + K * SizeOfVar

SizeOfVar - , .





, , , :





X = (N + 0 * SizeOfVar) * 13914 = N * 13914

, , , .





X = (N + 5 * SizeOfVar) * 8945

- . , .





N * 13914 = (N + 5 * SizeOfVar) * 8945

. - N SizeOfVar. N - , SizeOfVar? , , , "number", , , .





- " JavaScript 64- . 8 , 64/8 = 8 ." - . 8 . , N.





N * 13914 = (N + 5 * 8) * 8945

:





N * 13914 = N * 8945 + 40 * 8945

N, : N 72. 72 .





, N = 72 , , Chrome ... 1002128 . . , .





- , , ? , , 7 'number'. 





: , (72 + 7 * 8) , 128. 1002128 128 ... 7829! , 7829 !  ...





. 3. , . , , , - . - .



, , ExecutionStack Chrome 72 , - .



!





. .  . 45606 . 39905 . NodeJS Chrome . JavaScript. 





?

, Object? 





let i = 0;

const func = () => {
  const a = {
    key: i + 1,
  };
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}
      
      



. 12516. , . JS' - . , .





? ? *?

, . , . , , . , .





:

  • .





  • .





  • "" , .





  • .





: "number" , , ?








All Articles