Este artículo es un resumen del manual "Cómo funcionan los navegadores: Lo que hay detrás de los navegadores web actuales" escrito por Tali Garsiel y Paul Irish.
¿Cómo funcionan los navegadores?
Para
acceder a una página web necesitamos su ubicación. La URI es el identificador
de un archivo alojado en algún sitio de internet, esta identificación contiene
un nombre y una localización.
En algunos
casos solo se utiliza el nombre o la localización, para esto y evitar
confusiones a la hora de acceder a un archivo con su identificación (URI) se
crearon por separado la localización (URL) y nombre (URN) del archivo.
Entonces,
URI = Identificador del archivo, URL = Localización del archivo, URN = Nombre
del archivo.
Desde que
dos archivos pueden tener el mismo nombre la URN no es tan útil, por esto en la
mayoría de los casos se usa la URL.
Un poco más sobre la URL…
Para poder
pedir recursos a un servidor web, el protocolo HTTP usa la URL para identificar
la localización de la página web en el internet.
Las URL
tienen dos campos requeridos: el protocolo y el dominio. Además, tiene algunos
opcionales como el puerto, el path, queries y fragmentos.
http://www.example.com/people?fn=Link/#Place
Protocolo
Dominio
Path
Query
Fragmento
INTRODUCCIÓN
FUNCIÓN DE UN NAVEGADOR
La función
principal del navegador es pedir al servidor web la URI buscada por el cliente,
renderizar la página bien sea un archivo HTML, PDF, imagen u otro tipo para
posteriormente mostrarla en pantalla.
La manera
en cómo se interpretan y muestran los archivos HTML viene por medio del
consorcio WC3 que determina las especificaciones HTML, CSS y los estándares de
internet. Los navegadores cumplen en mayor o menor medida estas
especificaciones, algunos añadiendo funciones únicas como el administrador de
descargas de Firefox.
Componentes principales
1. Interfaz de usuario: Incluye en general toda la parte visible para el usuario.
2. Motor de búsqueda: Coordina acciones entre la interfaz y el motor de renderización.
3. Motor de renderización: Es responsable de analizar el contenido solicitado por el cliente como HTML y CSS para mostrarlo luego en pantalla.
4. Red: Es el responsable de las llamadas que corresponden a la red, como son las peticiones HTTP.
5. Servidor de la interfaz: Permite presentar widgets básicos como ventanas.
6. Intérprete de JavaScript: Permite interpretar y ejecutar código JavaScript.
7. Almacenamiento de datos: Es una ligera, pero completa base de datos que almacenan los navegadores en el dispositivo como son las cookies.
MOTOR DE RENDERIZACIÓN
Los
navegadores populares están basados en dos motores de renderización, Firefox en
Gecko propio de Mozilla y WebKit de código abierto presente en Chrome.
Flujo:
1. Empieza recibiendo el contenido solicitado desde la capa de red (Este contenido llega por partes generalmente de 8.000 bytes)
2. Analiza y convierte las etiquetas del HTML en nodos DOM y crea un “árbol de contenido”
3. Analiza los estilos CSS junto a instrucciones visuales del HTML y crea otro “árbol de renderización”
4. El árbol de renderización contiene rectángulos con atributos visuales como el color y dimensiones y estos están organizados en el orden que deben aparecer en pantalla
5. Una vez creado el árbol de renderización, se inicia una etapa de “diseño” donde se le asignará a cada elemento las coordenadas donde deben ir.
6. Ahora una etapa de “pintura” en donde se recorrerán los elementos y se pintarán.
7. Este proceso es gradual, por tanto, el motor de renderización no esperará a que llegue todo el contenido de la red para empezar a analizar y mostrar en pantalla por partes. Esto se hace con intención de mostrar lo más pronto en pantalla el contenido y mejorar la experiencia de usuario
El flujo
entre WebKit y Gecko de Mozilla es básicamente el mismo, aunque con diferencias
en la terminología. Analizar un archivo significa convertir el código HTML en
una estructura que tenga sentido, el resultado es un árbol de nodos que
representa la estructura del archivo. Generalmente, se le denomina “árbol de
análisis”.
Ejemplo: el árbol de análisis de la expresión 2 + 3 – 1 podría ser este:
ANÁLISIS
El
análisis del documento se rige por unas reglas gramaticales libres de contexto,
estas reglas son el lenguaje o formato en el que está escrito el documento.
Todos los formatos deben tener una determinada gramática: un vocabulario y
reglas de sintaxis.
Este
analizador puede descomponerse entonces, en dos partes: análisis léxico
(vocabulario) y análisis sintáctico (sintaxis).
Análisis sintáctico: Es la aplicación de las reglas sintácticas del lenguaje, es decir, comprueba que el documento este escrito gramaticalmente correctamente. Es capaz de ignorar caracteres irrelevantes como espacios en blanco y saltos de línea.
También podemos añadir otro tipo de análisis, el semántico que comprueba que no haya inconsistencias o contradicciones, por ejemplo: Jorge es un soltero casado, pero normalmente los analizadores se dividen el trabajo entre un analizador léxico responsable de descomponer los datos a tokens y el analizador normal que es responsable de tras comprobar las reglas sintácticas del lenguaje crear el árbol de análisis.
El
análisis es un proceso iterativo, este irá de la siguiente manera:
1. El analizador pedirá al analizador léxico un token
2. Buscará una coincidencia del token con las reglas de sintaxis
3. Si encuentra una regla añadirá un nodo correspondiente al token al árbol de análisis
4. Si no encuentra la regla, almacenará al token internamente y pedirá otro token
5. Buscará entonces reglas correspondientes a los tokens almacenados internamente, si no hay ninguna regla lanzará una excepción, es decir, invalidará el documento por contener errores de sintaxis.
Traducción: Muchas veces el árbol de análisis
no es el producto final. El árbol de análisis pasa por un proceso de traducción
a otro formato, como pasa en los compiladores que el árbol de análisis pasa por
una traducción a código máquina.
Ejemplo
con 2 + 3 – 1
Vocabulario:
El lenguaje puede incluir números enteros, el signo positivo (+) y negativo (-)
Reglas de
sintaxis:
1. Los bloques de construcción serán términos, expresiones y operaciones
2. Puede incluir cualquier cantidad de expresiones.
3. Una expresión es igual a un término seguido de una operación y de otro término
4. Una operación es un token de suma o resta
5. Un término es un token de número entero o una expresión
Al
analizar la entrada 2 + 3 – 1
- La primera coincidencia que tenemos está en la regla 5, con el término “2”
- La segunda está en la expresión “2 + 3” que está en la regla 3
- La siguiente será la expresión total que estará al final de analizar toda la entrada “2 + 3 – 1”
Un error que invalidaría la ejecución sería la expresión “2 + +”
ANALIZADOR HTML
Este se
encarga de analizar las etiquetas HTML y organizarlas en un árbol de análisis;
la sintaxis y el vocabulario son especificados por W3C
El
lenguaje HTML no se puede analizar fácilmente por analizadores convencionales,
puesto a que HTML es un lenguaje “permisivo”, ósea, tiene una sintaxis
flexible. Existe un formato formal para definir al lenguaje HTML: DTD, pero no
es una gramática libre de contexto.
DOM
El árbol de salida o árbol de análisis está formado por elementos DOM y nodos de atributo. DOM son las siglas de “Document Object Model”.
Nodos: Es cualquier etiqueta presente en el cuerpo, como un párrafo o la etiqueta <body>
Ejemplo del árbol de análisis con el marcado de HTML:
<html>
<body>
<p> Hello World </p>
<div> <img src=”example.png” /> </div>
</body>
</html>
El algoritmo del analizador personalizado de HTML tiene bastante complejidad, por los estados en los que incurre la ejecución. Eventos como document.write cambian los tokens del documento, por tanto en una forma simplificada lo que hace este algoritmo es abrir un estado cada que encuentra un carácter “<”, luego identifica el nombre de la etiqueta “div”, analiza lo que haya dentro de la etiqueta y finalmente cierra el estado cuando encuentra “/>”.
Luego pasa
a la construcción del árbol usando un algoritmo, lo primero que sucede es que
se crea un objeto “Document” que es la raíz de todo y donde se añadirán los
elementos. Este constructor (algoritmo) añadirá cada nodo que entrega el token.
Algunos elementos se mantendrán activos para corregir errores de sintaxis.
Al
finalizar este análisis, el navegador marcará el documento como interactivo y
empezará a analizar las secuencias de comandos “aplazados”, es decir, aquellas
secuencias que deben ejecutarse luego de haber analizado el documento. Una vez
hecho esto el navegador establecerá el estado del documento como “completado” y
se activará un evento de “carga”.
Hay una
serie de errores convencionales que se infringen en los documentos, los
navegadores desarrollaron a través de los años una tolerancia a estos errores,
corrigiéndolos de la mejor manera posible.
Un ejemplo
es abrir una etiqueta que no existe “<mytag>hi</mytag>”, cerrar
desde el comienzo una etiqueta “</br>” etc.
ANÁLISIS CSS
A diferencia
de HTML, CSS tiene una gramática libre de contexto y puede analizarse con los
tipos anteriormente dichos: análisis léxico y sintáctico.
Escribir manualmente
un analizador es una tarea compleja, por esto existen generadores de
analizadores que crean análisis léxico y sintáctico automáticamente. WebKit utiliza
los generadores de analizadores Flex y Bison mientras que Firefox utiliza uno
escrito manualmente; en ambos casos los archivos CSS se analizan y se
convierten en objetos “StyleSheet”, cada uno contiene reglas gramáticas de CSS.
SECUENCIA DE COMANDOS (JavaScript)
El modelo
de la web es sincrónico
1. Se espera que los comandos sean analizados para que se ejecuten inmediatamente el analizador llegué a la etiqueta <script>
2. El análisis del documento será detenido hasta que la secuencia de comandos sea ejecutada.
3. La secuencia de comandos es externa, por lo que es necesario recuperar el archivo de la red. También de forma síncrono, ósea, se detiene el análisis hasta recuperar el archivo.
Este
modelo fue utilizado durante muchos años, ahora los desarrolladores pueden
marcar la secuencia de comando como “aplazada”. Así, no se detiene el análisis del
documento y la secuencia se ejecuta una vez se haya completado el análisis.
HTML5,
además, añade una opción que permite marcar la secuencia de comandos como
ejecución asíncrona para que se analice y ejecute en un subproceso distinto.
ANALISIS
ESPECULATIVO: Este
análisis se hace en paralelo al análisis principal, se encarga de cargar y
analizar los recursos externos en subprocesos para mejorar la velocidad de
carga, no modifica el DOM.
Las hojas
de estilo (CSS), deben analizarse primero a la secuencia de comandos
(JavaScript). Esto es por qué en ocasiones, los comandos hacen solicitud de información
de estilos durante la fase de análisis del documento. Esto incurre en errores
si no se ha completado la carga o análisis de los estilos, por esto Firefox
bloquea la secuencia de comandos si todavía se están cargando los estilos mientras
que WebKit bloquea comandos que hagan alusión a propiedades de estilo.
ÁRBOL DE RENDERIZACIÓN
A la vez
que se construye el árbol DOM, el navegador construye este árbol de renderización.
Este árbol esta formado por los elementos visuales en el orden que se esperan
mostrar, su propósito es representar el contenido en el orden correcto. Los
elementos de este árbol pueden llamarse “frames” (En Firefox) o “render” (En WebKit).
ÁRBOL DOM Y ÁRBOL DE RENDERIZACIÓN
Los render
corresponden a elementos DOM, pero no uno a uno. Elementos no visuales como <head>
o con atributo de visualización “none” no son insertados en el árbol de renderización.
Algunos elementos
DOM corresponden a múltiples render por su complejidad, como lo son la etiqueta
<select> que dispone de tres render: uno para el área de visualización,
otro para la lista desplegable y otro para el botón.
Al
procesar las etiquetas <html> y <body>, se construye la raíz del
árbol de renderización este es el “bloque contenedor” donde estarán todos los
otros bloques (elementos) insertados de los nodos DOM.
DISEÑO
Cuando el render se crea y se añade al árbol, no tiene posición ni
tamaño. El cálculo de esto valores se conoce como diseño o reflujo, cada render
tiene un método de “diseño”.
Este proceso conlleva cálculos geométricos que se realizan una sola
vez, pues los elementos posteriores no suelen influir en la geométrica de los
anteriores, por lo que el diseño puede aplicarse en un marco de coordenadas que
van de izquierda a derecha y de arriba a abajo en el documento. Aunque hay
excepciones, como las tablas HTML que conllevan más de un cálculo.
Para no iniciar un proceso de diseño completo con cada pequeña
modificación, el navegador utiliza un sistema de modificación (dirty bit).
Cuando se añade o modifica un render se marca con un indicador “dirty”, lo que
significa que se debe someter a un proceso de diseño.
Cuando se activa un proceso de diseño por un cambio de tamaño o
posición del render, el tamaño se toma de una caché en lugar de recalcularse. En
cambios locales, como la inserción de texto en campos de texto, el proceso de
diseño solo modificará un subárbol y no modifica a los elementos que lo rodean,
de lo contrario cada tecla activaría un diseño completo del documento.
PINTURA
En esta
fase se recorre el árbol de renderización y se activa el método “pintura” del
render para que muestre su contenido en pantalla. Igualmente, que en el diseño
hay un proceso global que conlleva la “pintura” de la totalidad del árbol y
otro proceso incremental, en el que los render se modifican de una forma que no
afecte todo el árbol.
Los navegadores intentan ejecutar la menor cantidad de acciones
posibles cuando se produce un cambio, por tanto, si hay cambios en el color de
un elemento se pintará solamente ese elemento. Si hay cambios en la posición,
se diseña y pinta nuevamente solo ese elemento y sus secundarios. Si se añade
un nuevo nodo DOM se activará un proceso de diseño y pintura de ese nodo. Y en
cambios de mayor importancia como el cambio de fuente se invalidarán las cachés
para luego activarse un proceso de pintura y diseño del árbol completo.
SUBPROCESOS DEL MOTOR DE RENDERIZACIÓN
El motor de renderización ocurre generalmente en un único subproceso.
Casi todas las operaciones, excepto las de red se generan en un único subproceso.
En Firefox y Safari es el subproceso principal del navegador, mientras que en Chrome
es el subproceso principal del proceso de pestaña.
Los procesos de red se pueden realizan paralelamente en varios
subprocesos, pero es limitado normalmente de dos a seis conexiones.
El subproceso principal es un bucle infinito que mantiene el proceso
activo. Espera eventos como diseño y pintura para procesar.