El mes pasado escribí un artículo sobre cómo V8 ejecuta el código JavaScript (let a = 1). , Después de escribirlo, descubrí que sé muy poco sobre el conocimiento de bajo nivel del motor V8 de herramientas de uso común. Al mismo tiempo, mi tiempo real en front-end es relativamente corto, por lo que la base también es muy débil. Combinando lo anterior, planeo aprender y comprender desde la perspectiva de nivel inferior cuando tenga tiempo, para comprender y resolver los problemas encontrados durante el proceso de uso, comprender la esencia de JavaScript y poder aprender JavaScript mejor. Si tienes la misma confusión que yo, entonces podemos ir juntos y aprender juntos.
En esta serie, continuaré resumiendo desde mi perspectiva:
prefacio
A través de este artículo puedes aprender lo siguiente:
1、为什么会存在栈溢出?
2、调用栈的定义
3、执行上下文的管理方式
4、调用栈的作用
1. Desbordamiento de memoria
Primero veamos un código de llamada recursivo simple.
<script>
function recursion(x) {
console.log(x)
recursion(x)
}
recursion(1)
</script>
El resultado de la ejecución es el siguiente
Es decir, mi computadora de prueba recurrió aproximadamente 11421 veces y luego la pila se desbordó. El número de 11421 puede variar según la configuración de la computadora. Se excedió el tamaño máximo de la pila de llamadas Se excedió el tamaño máximo de la pila de llamadas.
El problema ya está ahí, ¿por qué está dando un error? Con esta pregunta en mente, seguimos mirando hacia abajo.
2. Dos formas de ver la pila de llamadas
Veamos otra pieza de código.
<script>
var a = 10
function add_d() {
var d = 40
console.trace('add_d正在执行')
return a + d
}
function add_c() {
var c = 30
var dd = add_d()
console.trace('add_d已经执行结束,从call stack弹出')
return c + dd
}
function add_b() {
var b = 20
let cc = add_c()
console.trace('add_c已经执行结束,从call stack弹出')
return b + cc
}
add_b()
console.trace('add_b已经执行结束,从call stack弹出')
</script>
Captura de pantalla después de ejecutar el código
En la primera forma, puede dividir el punto en la línea 5 (la posición de la línea del código en la captura de pantalla) a través de la captura de pantalla y puede ver la información de la pila de llamadas actual en el lado derecho.
La segunda forma es a través de console.trace(), el código anterior en realidad ha agregado el registro de impresión, que se puede ver directamente
console.trace
add_d @ js执行过程.html:16
add_c @ js执行过程.html:22
add_b @ js执行过程.html:27
(匿名) @ js执行过程.html:30 // 这里的匿名相当于全局进行
js执行过程.html:16 add_d正在执行
add_d @ js执行过程.html:16
add_c @ js执行过程.html:22
add_b @ js执行过程.html:29
(匿名) @ js执行过程.html:34
js执行过程.html:23 add_d已经执行结束,从call stack弹出
add_c @ js执行过程.html:23
add_b @ js执行过程.html:29
(匿名) @ js执行过程.html:34
js执行过程.html:30 add_c已经执行结束,从call stack弹出
add_b @ js执行过程.html:30
(匿名) @ js执行过程.html:34
js执行过程.html:35 add_b已经执行结束,从call stack弹出
(匿名) @ js执行过程.html:35
Al imprimir el registro, podemos saber más claramente que cuando se ejecuta la función actual, se eliminará automáticamente del registro de impresión.
También puede ajustar el orden de console.trace() para ver cuál es el orden de las inserciones en la pila de llamadas. He aquí un breve resumen de mi experiencia actual:
-
当JavaScript调用一个函数的时候,JavaScript引擎遍会为其创建
执行上下文
,并把该执行上下文
压入调用栈
,然后JavaScript引擎开始执行函数的代码。 -
执行函数时如果又发现有函数被调用,则会继续将该函数的
执行上下文
压入调用栈
,然后继续开始执行函数中的代码。 -
以此类推......
-
当某个函数执行完毕的时候,JavaScript引擎会将函数的
执行上下文
弹出栈。 -
当
调用栈
的空间满了以后,就会引发堆栈溢出
的问题。
因为调用栈的空间是有限的,所以我们开篇里的小例子不断的递归,根本停不下来,迟早会发生栈溢出,也就是我上面截图的错误。
3、调用栈的定义
我们先来理解一下栈的数据结构,通过一个小故事来进行简单的理解:
自助餐厅有一堆餐盘,工作人员洗好之后,将一批餐盘一个一个的叠加到一起,由于各种原因(餐盘的摆放位置、以及方便客人拿取等等),每批餐盘都有一定的高度限制,肯定不能无限高。接下来我们就来分析其中一批被叠拼摆好的餐盘吧,先假设一下餐盘的高度是35(总共摆放了35个餐盘)
-
每次将餐盘叠拼上去的时候就相当于入栈
-
这个操作一直执行了35次,因为一直没有使用
-
接着到中午开始排队吃饭的时候,到了取餐盘的地方,就有人开始从顶部取走一个餐盘(一般都是从顶部取,特殊情况这里我们就不讨论了)
-
每次取餐盘的操作就相当于出栈
-
这个操作一直执行了35次,因为排队吃饭就要使用餐盘,就要使用
-
最终35个餐盘都被取走了
可以发现,先被叠拼的餐盘,要最后才被取出,而刚被叠拼的餐盘,第一个就被拿走了。遵循的原则便是:
先进后出、后进先出
的原则。
La pila de llamadas es una estructura de datos que realiza un seguimiento de dónde estamos en el programa. Si ejecutamos una función, el motor de JavaScript realmente la creará para la función actual 函数执行上下文
en 函数执行上下文
ese momento y la colocará en la parte superior de la pila. Al regresar de esta función, la mostrará 函数执行上下文
desde la parte superior de la pila . Esto es lo que hace la pila de llamadas. Es decir, 执行上下文
se 调用栈
gestiona a través.
Resumir
-
调用栈
El espacio de almacenamiento es limitado. Si continúa empujándolo en la pila y lo empuja dentro de la pila, habrá un error de desbordamiento de memoria. -
执行上下文
se almacena调用栈
en -
调用栈
Comprender el funcionamiento de JavaScript desde la perspectiva de执行上下文
Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .