JavaScript e o Navegador

O sonho por trás da web é de um espaço comum de informação no qual nos comunicamos compartilhando informações. Sua universalidade é essencial: o fato de que um link de hipertexto pode apontar para qualquer coisa, seja pessoal, local ou global, seja um rascunho ou algo altamente refinado.

Tim Berners-Lee, The World Wide Web: A Very Short Personal History
Ilustração mostrando uma central telefônica

Os próximos capítulos deste livro irão discutir navegadores. Sem navegadores, não haveria JavaScript—ou, se houvesse, ninguém jamais teria prestado atenção nele.

A tecnologia da web foi descentralizada desde o início, não apenas tecnicamente, mas também em termos da forma como evoluiu. Vários fornecedores de navegadores adicionaram novas funcionalidades de maneiras ad hoc e, às vezes, mal planejadas, que depois—às vezes—eram adotadas por outros e, por fim, estabelecidas em padrões.

Isso é ao mesmo tempo uma bênção e uma maldição. Por um lado, é empoderador não ter uma parte central controlando um sistema, mas sim vê-lo sendo melhorado por várias partes trabalhando com pouca colaboração (ou, ocasionalmente, em hostilidade aberta). Por outro lado, a maneira desordenada com que a web foi desenvolvida significa que o sistema resultante não é exatamente um exemplo brilhante de consistência interna. Algumas partes são francamente confusas e mal projetadas.

Redes e a Internet

Redes de computadores existem desde a década de 1950. Se você conectar cabos entre dois ou mais computadores e permitir que eles enviem dados de um lado para o outro por esses cabos, é possível fazer todo tipo de coisas maravilhosas.

Se conectar duas máquinas no mesmo prédio já nos permite fazer coisas incríveis, conectar máquinas ao redor de todo o planeta deve ser ainda melhor. A tecnologia para começar a implementar essa visão foi desenvolvida nos anos 1980, e a rede resultante é chamada de internet. Ela cumpriu sua promessa.

Um computador pode usar essa rede para enviar bits a outro computador. Para que qualquer comunicação efetiva surja desse envio de bits, os computadores em ambas as pontas precisam saber o que os bits devem representar. O significado de qualquer sequência de bits depende inteiramente do tipo de coisa que ela está tentando expressar e do mecanismo de codificação usado.

Um protocolo de rede descreve um estilo de comunicação em uma rede. Existem protocolos para envio de email, para recebimento de email, para compartilhamento de arquivos e até para controlar computadores que estejam infectados por software malicioso.

O HyperText Transfer Protocol (HTTP) é um protocolo para recuperar recursos nomeados (partes de informação, como páginas web ou imagens). Ele especifica que o lado que faz a requisição deve começar com uma linha como esta, nomeando o recurso e a versão do protocolo que está tentando usar:

GET /index.html HTTP/1.1

Há muitas outras regras sobre a forma como quem faz a requisição pode incluir mais informações na requisição e a forma como o outro lado, que retorna o recurso, empacota seu conteúdo. Veremos o HTTP com um pouco mais de detalhe no Capítulo 18.

A maioria dos protocolos é construída sobre outros protocolos. O HTTP trata a rede como um dispositivo semelhante a um fluxo no qual você pode colocar bits e fazê-los chegar ao destino correto na ordem correta. Fornecer essas garantias sobre o envio primitivo de dados que a rede oferece já é um problema bastante complicado.

O Transmission Control Protocol (TCP) é um protocolo que resolve esse problema. Todos os dispositivos conectados à internet “falam” esse protocolo, e a maior parte da comunicação na internet é construída sobre ele.

Uma conexão TCP funciona da seguinte forma: um computador deve estar aguardando, ou escutando, para que outros computadores comecem a se comunicar com ele. Para poder escutar diferentes tipos de comunicação ao mesmo tempo em uma única máquina, cada escuta possui um número (chamado de porta) associado a ela. A maioria dos protocolos especifica qual porta deve ser usada por padrão. Por exemplo, quando queremos enviar um email usando o protocolo SMTP, espera-se que a máquina através da qual o enviamos esteja escutando na porta 25.

Outro computador pode então estabelecer uma conexão conectando-se à máquina de destino usando o número de porta correto. Se a máquina de destino puder ser alcançada e estiver escutando nessa porta, a conexão é criada com sucesso. O computador que está escutando é chamado de servidor, e o computador que se conecta é chamado de cliente.

Tal conexão funciona como um canal bidirecional pelo qual bits podem fluir—as máquinas em ambas as pontas podem inserir dados nele. Uma vez que os bits são transmitidos com sucesso, eles podem ser lidos pela máquina do outro lado. Este é um modelo conveniente. Pode-se dizer que o TCP fornece uma abstração da rede.

A Web

A World Wide Web (não confundir com a internet como um todo) é um conjunto de protocolos e formatos que nos permitem visitar páginas web em um navegador. A palavra Web refere-se ao fato de que essas páginas podem facilmente se ligar umas às outras, formando uma enorme malha pela qual os usuários podem navegar.

Para se tornar parte da web, tudo o que você precisa fazer é conectar uma máquina à internet e fazê-la escutar na porta 80 usando o protocolo HTTP, para que outros computadores possam solicitar documentos a ela.

Cada documento na web é nomeado por um uniform resource locator (URL), que se parece com algo assim:

  http://eloquentjavascript.net/13_browser.html
 |      |                      |               |
 protocolo     servidor            caminho

A primeira parte nos diz que essa URL usa o protocolo HTTP (em oposição, por exemplo, ao HTTP criptografado, que seria https://). Em seguida vem a parte que identifica de qual servidor estamos solicitando o documento. Por último há uma string de caminho que identifica o documento (ou recurso) de interesse.

Máquinas conectadas à internet recebem um endereço IP, um número que pode ser usado para enviar mensagens a essa máquina, e que se parece com algo como 149.210.142.219 ou 2001:4860:4860::8888. Como listas de números mais ou menos aleatórios são difíceis de lembrar e incômodas de digitar, você pode registrar um nome de domínio para um endereço ou conjunto de endereços. Eu registrei eloquentjavascript.net para apontar para o endereço IP de uma máquina que controlo e, assim, posso usar esse nome de domínio para servir páginas web.

Se você digitar essa URL na barra de endereços do seu navegador, ele tentará recuperar e exibir o documento nessa URL. Primeiro, seu navegador precisa descobrir a que endereço eloquentjavascript.net se refere. Em seguida, usando o protocolo HTTP, ele fará uma conexão com o servidor nesse endereço e solicitará o recurso /13_browser.html. Se tudo correr bem, o servidor envia de volta um documento, que então é exibido na sua tela.

HTML

HTML, que significa HyperText Markup Language, é o formato de documento usado para páginas web. Um documento HTML contém texto, assim como tags que dão estrutura ao texto, descrevendo coisas como links, parágrafos e títulos.

Um documento HTML curto pode se parecer com isto:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>My home page</title>
  </head>
  <body>
    <h1>My home page</h1>
    <p>Hello, I am Marijn and this is my home page.</p>
    <p>I also wrote a book! Read it
      <a href="http://eloquentjavascript.net">here</a>.</p>
  </body>
</html>

As tags, envolvidas por colchetes angulares (< e >, os símbolos de menor que e maior que), fornecem informações sobre a estrutura do documento. O outro texto é apenas texto simples.

O documento começa com <!doctype html>, que informa ao navegador para interpretar a página como HTML moderno, em oposição a estilos obsoletos usados no passado.

Documentos HTML têm um head (cabeça) e um body (corpo). O head contém informações sobre o documento, e o body contém o próprio documento. Neste caso, o head declara que o título deste documento é “My home page” e que ele usa a codificação UTF-8, que é uma forma de codificar texto Unicode como dados binários. O body do documento contém um título (<h1>, significando “heading 1”—<h2> até <h6> produzem subtítulos) e dois parágrafos (<p>).

As tags aparecem em várias formas. Um elemento, como o body, um parágrafo ou um link, é iniciado por uma tag de abertura como <p> e finalizado por uma tag de fechamento como </p>. Algumas tags de abertura, como a de link (<a>), contêm informações extras na forma de pares nome="valor". Esses são chamados de atributos. Neste caso, o destino do link é indicado com href="http://eloquentjavascript.net", onde href significa “hypertext reference”.

Alguns tipos de tags não envolvem nada e, portanto, não precisam ser fechados. A tag de metadados <meta charset="utf-8"> é um exemplo disso.

Para poder incluir colchetes angulares no texto de um documento, mesmo que eles tenham um significado especial em HTML, outra forma de notação especial precisa ser introduzida. Um colchete angular de abertura é escrito como &lt; (“menor que”), e um de fechamento é escrito como &gt; (“maior que”). Em HTML, um caractere E comercial (&) seguido por um nome ou código de caractere e um ponto e vírgula (;) é chamado de entidade e será substituído pelo caractere que representa.

Isso é análogo à forma como barras invertidas são usadas em strings JavaScript. Como esse mecanismo também dá um significado especial ao caractere E comercial (&), ele precisa ser escapado como &amp;. Dentro de valores de atributos, que são delimitados por aspas duplas, &quot; pode ser usado para inserir um caractere de aspas literal.

O HTML é interpretado de uma forma surpreendentemente tolerante a erros. Quando tags que deveriam estar presentes estão ausentes, o navegador as adiciona automaticamente. A forma como isso é feito foi padronizada, e você pode contar com todos os navegadores modernos para fazê-lo da mesma maneira.

O documento a seguir será tratado exatamente como o mostrado anteriormente:

<!doctype html>

<meta charset=utf-8>
<title>My home page</title>

<h1>My home page</h1>
<p>Hello, I am Marijn and this is my home page.
<p>I also wrote a book! Read it
  <a href=http://eloquentjavascript.net>here</a>.

As tags <html>, <head> e <body> desapareceram completamente. O navegador sabe que <meta> e <title> pertencem ao head e que <h1> significa que o body começou. Além disso, não estou mais fechando explicitamente os parágrafos, já que abrir um novo parágrafo ou encerrar o documento os fechará implicitamente. As aspas ao redor dos valores dos atributos também desapareceram.

Este livro geralmente omitirá as tags <html>, <head> e <body> dos exemplos para mantê-los curtos e sem poluição visual. Ainda assim, vou fechar as tags e incluir aspas ao redor dos atributos.

Também normalmente omitirei a declaração de doctype e charset. Não interprete isso como um incentivo para removê-los de documentos HTML. Navegadores frequentemente fazem coisas absurdas quando você se esquece deles. Considere o doctype e os metadados charset como implicitamente presentes nos exemplos, mesmo quando não aparecem de fato no texto.

HTML e JavaScript

No contexto deste livro, a tag HTML mais importante é <script>, que nos permite incluir um trecho de JavaScript em um documento.

<h1>Testing alert</h1>
<script>alert("hello!");</script>

Esse script será executado assim que sua tag <script> for encontrada enquanto o navegador lê o HTML. Esta página exibirá uma caixa de diálogo ao ser aberta—a função alert se assemelha a prompt, no sentido de que abre uma pequena janela, mas apenas mostra uma mensagem sem solicitar entrada.

Incluir programas grandes diretamente em documentos HTML costuma ser impraticável. A tag <script> pode receber um atributo src para buscar um arquivo de script (um arquivo de texto contendo um programa JavaScript) a partir de uma URL.

<h1>Testing alert</h1>
<script src="code/hello.js"></script>

O arquivo code/hello.js incluído aqui contém o mesmo programa—alert("hello!"). Quando uma página HTML referencia outras URLs como parte de si mesma, como um arquivo de imagem ou um script, os navegadores irão buscá-los imediatamente e incluí-los na página.

Uma tag de script deve sempre ser fechada com </script>, mesmo que ela apenas referencie um arquivo de script e não contenha código. Se você esquecer isso, o restante da página será interpretado como parte do script.

Você pode carregar ES modules (veja o Capítulo 10) no navegador fornecendo à sua tag de script um atributo type="module". Esses módulos podem depender de outros módulos usando URLs relativas a si mesmos como nomes de módulo em declarações import.

Alguns atributos também podem conter um programa JavaScript. A tag <button> (que aparece como um botão) suporta um atributo onclick. O valor do atributo será executado sempre que o botão for clicado.

<button onclick="alert('Boom!');">DO NOT PRESS</button>

Observe que precisei usar aspas simples para a string no atributo onclick, porque aspas duplas já são usadas para delimitar todo o atributo. Eu também poderia ter usado &quot; para escapar as aspas internas.

No sandbox

Executar programas baixados da internet é potencialmente perigoso. Você não sabe muito sobre as pessoas por trás da maioria dos sites que visita, e elas não necessariamente têm boas intenções. Executar programas de agentes maliciosos é como seu computador é infectado por vírus, seus dados são roubados e suas contas são invadidas.

Ainda assim, o atrativo da web é que você pode navegá-la sem necessariamente confiar em todas as páginas que visita. É por isso que os navegadores limitam severamente o que um programa JavaScript pode fazer: ele não pode acessar arquivos no seu computador nem modificar nada que não esteja relacionado à página web na qual foi incorporado.

Isolar um ambiente de programação dessa forma é chamado de sandbox, a ideia sendo que o programa está brincando de forma inofensiva em uma caixa de areia. Mas você deve imaginar esse tipo específico de sandbox como tendo uma gaiola de barras de aço grossas sobre ele, para que os programas que estão lá dentro não possam realmente sair.

A parte difícil do sandboxing é permitir que os programas tenham liberdade suficiente para serem úteis, ao mesmo tempo em que se restringe qualquer comportamento perigoso. Muitas funcionalidades úteis, como comunicar-se com outros servidores ou ler o conteúdo da área de transferência, também podem ser usadas para fins problemáticos, que invadem a privacidade.

De vez em quando, alguém descobre uma nova maneira de contornar as limitações de um navegador e fazer algo prejudicial, variando de vazar pequenas informações privadas até assumir o controle completo da máquina em que o navegador está rodando. Os desenvolvedores de navegadores respondem corrigindo a falha, e tudo volta ao normal—até que o próximo problema seja descoberto e, esperamos, divulgado publicamente em vez de explorado secretamente por alguma agência governamental ou organização criminosa.

Compatibilidade e as guerras dos navegadores

Nos estágios iniciais da web, um navegador chamado Mosaic dominava o mercado. Após alguns anos, o equilíbrio mudou para o Netscape, que, por sua vez, foi amplamente substituído pelo Internet Explorer da Microsoft. Em qualquer momento em que um único navegador dominava, seu fornecedor se sentia no direito de inventar unilateralmente novos recursos para a web. Como a maioria dos usuários utilizava o navegador mais popular, os sites simplesmente começavam a usar esses recursos—sem se importar com os outros navegadores.

Essa foi a era sombria da compatibilidade, frequentemente chamada de guerras dos navegadores. Desenvolvedores web ficaram com não uma web unificada, mas duas ou três plataformas incompatíveis. Para piorar, os navegadores em uso por volta de 2003 estavam todos cheios de bugs, e, claro, os bugs eram diferentes para cada navegador. A vida era difícil para quem escrevia páginas web.

O Mozilla Firefox, um projeto sem fins lucrativos derivado do Netscape, desafiou a posição do Internet Explorer no final dos anos 2000. Como a Microsoft não estava particularmente interessada em se manter competitiva na época, o Firefox conquistou uma grande fatia do mercado. Por volta do mesmo período, o Google lançou seu navegador Chrome e o navegador Safari da Apple ganhou popularidade, levando a uma situação com quatro grandes participantes, em vez de apenas um.

Os novos participantes tinham uma postura mais séria em relação a padrões e melhores práticas de engenharia, resultando em menos incompatibilidades e menos bugs. A Microsoft, vendo sua participação de mercado despencar, mudou de postura e adotou essas práticas em seu navegador Edge, que substituiu o Internet Explorer. Se você está começando a aprender desenvolvimento web hoje, considere-se com sorte. As versões mais recentes dos principais navegadores se comportam de maneira bastante uniforme e têm relativamente poucos bugs.

Infelizmente, com a participação de mercado do Firefox ficando cada vez menor, e o Edge tendo se tornado apenas um invólucro em torno do núcleo do Chrome em 2018, essa uniformidade pode mais uma vez assumir a forma de um único fornecedor—o Google, desta vez—tendo controle suficiente sobre o mercado de navegadores para impor sua visão de como a web deve ser ao resto do mundo.

Por mais que valha, essa longa cadeia de eventos históricos e acidentes produziu a plataforma web que temos hoje. Nos próximos capítulos, vamos escrever programas para ela.