diff options
Diffstat (limited to 'files/pt-br/learn/javascript/asynchronous/introdução/index.html')
-rw-r--r-- | files/pt-br/learn/javascript/asynchronous/introdução/index.html | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/files/pt-br/learn/javascript/asynchronous/introdução/index.html b/files/pt-br/learn/javascript/asynchronous/introdução/index.html new file mode 100644 index 0000000000..b95a88d35c --- /dev/null +++ b/files/pt-br/learn/javascript/asynchronous/introdução/index.html @@ -0,0 +1,283 @@ +--- +title: Introdução ao JavaScript Async +slug: Learn/JavaScript/Asynchronous/Introdução +translation_of: Learn/JavaScript/Asynchronous/Introducing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div> + +<div>Neste artigo nós recapitulamos brevemente os problemas que são associados com o JavaScript síncrono, e dar uma primeira olhada em algumas das diferentes técnicas assíncronas que você vai encontrar, mostrando como elas podem nos ajudar a resolver tais problemas.</div> + +<div></div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Conhecimentos básicos de informática e sobre os fundamentos do JavaScript.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Ganhar familiaridade com o que é o Js assíncrono e como ele se difere do Js síncrono.</td> + </tr> + </tbody> +</table> + +<h2 id="JavaScript_síncrono">JavaScript síncrono</h2> + +<p>Para entendermos o que é o <strong>{{Glossary("asynchronous")}}</strong> JavaScript, nós primeiro temos que ter certeza que entedemos o que é o <strong>{{Glossary("synchronous")}}</strong> JavaScript. Essa seção revê um pouco das informações que nós vimos no artigo anterior.</p> + +<p>Muitas das funcionalidades que nós vimos em áreas anteriores são síncronas — você executa um código, e o reultado é retornado assim que o navegador puder. Vamos ver um exemplo simples (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/basic-function.html">veja aqui</a>, e <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/basic-function.html">veja o código fonte</a>):</p> + +<pre class="brush: js">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + alert('Você clicou em mim!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'Este é um novo parágrafo adicionado'; + document.body.appendChild(pElem); +}); +</pre> + +<p>Neste bloco, as linhas são executadas uma após a outra:</p> + +<ol> + <li>Nós damos referência à um elemento {{htmlelement("button")}} que já está disponível na DOM.</li> + <li>Nós adicionamos um evento de <code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code>, e quando ele for clicado ele fará o seguinte: + <ol> + <li>Mostrar uma mensagem no <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code>.</li> + <li>Uma vez que o alert for dispensado, nós criamos um elemento {{htmlelement("p")}}.</li> + <li>Depois nós o preenchemos com um texto.</li> + <li>E finalmente, o adicionamos no body.</li> + </ol> + </li> +</ol> + +<p>Enquanro cada operação é processada, nada mais pode acontecer — a renderização é pausada. Isso acontece porque o JavaScript opera em uma única thread (<a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts#JavaScript_is_single_threaded">JavaScript é single threaded</a>). Apenas uma coisa pode acontecer por vez, em uma única thread principal, e tudo é bloqueado até que a operação seja concluída.</p> + +<p>Então, no exemplo acima, depois que você tenha clicado no botão, o parágrafo não vai aparecer até que o botão OK do alert seja pressionado. Tente isso com o botão a seguir:</p> + +<div class="hidden"> +<pre class="brush: html"><<span class="pl-ent">button</span>>Clique em mim</<span class="pl-ent">button</span>></pre> +</div> + +<p>{{EmbedLiveSample('Synchronous_JavaScript', '100%', '70px')}}</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: É importante lembrar que, mesmo sendo muito útil para demonstar uma situação de blocking, o <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> não é de bom uso em aplicativos reais.</p> +</div> + +<h2 id="Asynchronous_JavaScript">Asynchronous JavaScript</h2> + +<p>Por razões esclarecidas anteriormente (e.g. relativas ao blocking), muitas funcionalidades de APIs da Web agora usam código assíncrono na execução, especialmente aquelas que acessam ou buscam algum tipo de recurso de um dispositivo externo, como pegar um arquivo da rede, acessar um banco de dados e retornar dados dele, acessar uma stream de uma web cam, ou transmitir uma tela para um dispositivo VR.</p> + +<p>Por que é tão difícil trabalhar com isso usando códigos síncronos? Vamos dar uma olhada em um exemplo rápido. Quando você pega uma imagem de um servidor, você não pode retornar o resultado imediatamente. Isso significa que o pseudocódigo a seguir não poderia funcionar:</p> + +<pre class="brush: js">let resposta = fetch('myImage.png'); +let blob = resposta.blob(); +// Mostra sua imagem na UI</pre> + +<p>Isso acontece por que você não sabe quanto tempo a imagem levará para ser baixada, então quando você executar a segunda linha, ela vai resultar em um erro (provalvelmente sempre) porque a <code>resposta</code> não estará disponível ainda. Você precisa que o seu código espere até que a <code>resposta</code> seja retornada antes de fazer algo com ela.</p> + +<p>Existem dois tipos principais de estilo de código assíncrono que você encontrará no código JavaScript, as callbacks com um estilo old-school e código em um estilo das promises mais recente. Nas seções abaixo, revisaremos cada um deles por vez.</p> + +<h2 id="Callbacks_assíncronas">Callbacks assíncronas</h2> + +<p>Callback são funções que são passada como parâmetros na chamada de outra função que vai executar código por trás do panos. Quando esse código por trás dos panos terminar de ser executado, a função callback será chamada para te informar que a tarefa foi finalizada ou que algo do seu interesse aconteceu. O uso das callbacks é um pouco antiquado agora, mas você ainda pode vê-las em um número de APIs comumente usadas.</p> + +<p>Um exemplo de uma callback async é o segundo parâmetro do método {{domxref("EventTarget.addEventListener", "addEventListener()")}} (como vimos em ação anteriormente):</p> + +<pre class="brush: js">btn.addEventListener('click', () => { + alert('Você clicou em mim!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'Este é um novo parágrafo.'; + document.body.appendChild(pElem); +});</pre> + +<p>O primeiro parâmetro é o tipo de evento a ser executado e o segundo parâmetro é uma função callback que é chamada quando o evento é disparado.</p> + +<p>Quando passamos uma função callback como um parâmetro em outra função, nós apenas estamos passando a rêferencia da função como argumento, ou seja, a função callback <strong>não</strong><strong> é</strong> executada imediatamente. Ela é chamada de volta assíncronamente dentro do corpo da função que a contém, que é responsável por executar a função callback quando for necessário.</p> + +<p>Você pode escrever a sua própria função que contém uma callback facilmente. Vamos dar uma olhada em outro exemplo que carrega uma arquivo usando a <a href="/en-US/docs/Web/API/XMLHttpRequest">API <code>XMLHttpRequest</code> </a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/xhr-async-callback.html">veja aqui</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/xhr-async-callback.html">veja o código fonte</a>):</p> + +<pre class="brush: js">function loadAsset(url, type, callback) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = type; + + xhr.onload = function() { + callback(xhr.response); + }; + + xhr.send(); +} + +function displayImage(blob) { + let objectURL = URL.createObjectURL(blob); + + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +loadAsset('coffee.jpg', 'blob', displayImage);</pre> + +<p>Aqui nós criamos uma função <code>displayImage()</code> que simplesmente representa um blob que foi passada à ela como uma URL de objeto, e depois cria uma imagem para mostrar a URL, adicionando-a ao <code><body></code> do documento. Entretando, nós criamos depois uma função <code>loadAsset()</code> que pega uma callback como parâmetro, junto com uma URL a ser buscada e um tipo para o conteúdo. Ela usa o <code>XMLHttpRequest</code> (abreviação: "XHR") para buscar o recurso na URL dada, para depois passar a resposta para a callback para fazer algo com isso. Neste caso a callback está esperando o XHR terminar de baixar o recurso (usando o manipulador de eventos <code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code>) antes de passá-lo para a callback.</p> + +<p>Callback são versáteis — elas não apenas lhe permitem controlar a ordem em que as funções são executadas e quais dados são passados entre elas, elas também podem passar dados para diferentes funçoes dependendo das circunstâncias. Então você pode ter ações diferentes para executar na resposta baixada, como <code>processJSON()</code>, <code>displayText()</code>, etc.</p> + +<p>Note que nem todas as callback são assíncronas — algumas são executadas de um modo síncrono. Um exemplo é quando nós usamos o método {{jsxref("Array.prototype.forEach()")}} para iterar sobre os itens de uma array (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/foreach.html">veja aqui</a>, e a <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/foreach.html">fonte</a>):</p> + +<pre class="brush: js">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus']; + +gods.forEach(function (eachName, index){ + console.log(index + '. ' + eachName); +});</pre> + +<p>Neste exemplo nós iteramos sobra uma array de Deuses Gregos e imprimos o índice e seus valores no console. O parâmetro de <code>forEach()</code> é uma callback function, que por si só toma dois parâmetros: uma refêrencia ao nome da array e e os valores dos índices. Entretanto, ela não espera por algo para fazer a execução, pois isso acontece imediatamente</p> + +<h2 id="Promises">Promises</h2> + +<p>Promises são uma nova maneira de escrever código assíncrono que você verá em APIs Web modernas. Um bom exemplo disso é a API <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>, que é basicamente uma versão mais moderna e eficiente de {{domxref("XMLHttpRequest")}}. Vamos dar uma olhada em um exemplo rápido, do nosso artigo de <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Pegando dados do servidor</a>:</p> + +<pre class="brush: js">fetch('products.json').then(function(response) { + return response.json(); +}).then(function(json) { + products = json; + initialize(); +}).catch(function(err) { + console.log('Fetch problem: ' + err.message); +});</pre> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Você pode encontrar a versão finalizada no GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">veja aqui</a>, e também <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">seja a execução</a>).</p> +</div> + +<p>Aqui nós vemos <code>fetch</code><code>()</code> pegando um único parâmetro — a URL de um recurso que você quer pegar da rede — e retornando uma <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>. A promise é um objeto que representa a conclusão ou falha da operação assíncrona. Ela represente um estado intermediário, por assim dizer. É praticamente o jetio do navegador de dizer "Eu prometo voltar para você com a resposta o mais rápido possível", daí o nome "promessa".</p> + +<p>Você pode levar um tempo para se acostumar com esse conceito; Ele se parece um pouco com o {{interwiki("wikipedia", "Gato de Schrödinger")}} em ação. Nenhum dos possíveis resultados aconteceu ainda, então a operação fetch está esperando pelo resultado do navegador que vai completar a operação em algum ponto no futuro.</p> + +<p>Nós temos três blocos de código encadeados ao fim do <code>fetch()</code>:</p> + +<ul> + <li>Dois blocos <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code>. Ambos contém uma função callback que será executada se a operação anterior for executada, então você pode fazer algo com o resultado. Cada bloco <code>.then()</code> retorna outra promise, o que significa que você pode encadear múltiplos blocos <code>.then()</code> um ao outro, para que múltiplas operações assíncronas possam ser executadas uma atrás da outra.</li> + <li>O bloco <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> no final será executado em casos em que erros ocorrem quando um dos <code>.then()</code> falhe — de um modo similar aos blocos <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> síncronos, um objeto de erro fica disponível dentro do <code>catch()</code>, e pode ser usado para reportar erros que ocorreram. Note que o bloco <code>try...catch</code> não funcionará com promises, embora funcione com <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>, como você aprenderá mais adiante.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Você vai aprender mais sobre promises mais tarde no módulo, então não se preocupe se você não entendeu muito bem.</p> +</div> + +<h3 id="A_fila_de_eventos">A fila de eventos</h3> + +<p>Operações assíncronas como as promises são colocadas em uma <strong>fila de eventos</strong>, que é executada depois que a main thread terminar de ser processada. As operações serão completadas assim que for possível e depois retornam seus resultados para o ambiente JavaScript.</p> + +<h3 id="Promises_versus_callbacks">Promises versus callbacks</h3> + +<p>As promises tem algumas semelhanças com as callbacks. Elas são basicamente um objeto retornado em que você vincula funções callback, ao invés de passar as callbacks para uma função.</p> + +<p>Entretanto, as promises são feitas especificamente para lidarmos com operações async, e ter muitas vantagens sobre as velhas callbacks:</p> + +<ul> + <li>Você pode encadear múltiplas operações assíncronas usando múltiplos blocos <code>.then()</code>, passando o resultado de uma delas como o resultado como parâmetro da próxima operação. Isso é muito mais difícil de se fazer usando as callback, que normalmente termina em algo chamado de <a href="http://callbackhell.com/">callback hell</a>.</li> + <li>As callbacks das promises sempre são chamadas na ordem estrita em quesão colocadas na fila de eventos.</li> + <li>O tratamento de erros é muito melhor — todos os erros são tratados por um único bloco <code>.catch()</code> no final do encadeamento, ao invés de ser tratado individualmente em cada função callback.</li> + <li>Promessas evitam inversão de controle. Ao contrário das callbacks, que perdem totalmente o controle de como a função será executada quando passada para uma biblioteca de terceiros.</li> +</ul> + +<h2 id="A_natureza_do_código_assíncrono">A natureza do código assíncrono</h2> + +<p>Vamos explorar um exemplo que ilustra a natureza do código assíncrono, mostrando o que pode acontecer quando nós não estamos cientes da ordem de execução e dos problemas em tentar tratar código async como código síncrono. O exemplo a seguir é muito similar ao que vimos antes (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync.html">veja aqui</a>, e <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">a fonte</a>). Uma diferença e que nós icluimos um número de declarações {{domxref("console.log()")}} para ilustrar na ordem que você pensa que o código fosse executado.</p> + +<pre class="brush: js">console.log ('Starting'); +let image; + +fetch('coffee.jpg').then((response) => { + console.log('It worked :)') + return response.blob(); +}).then((myBlob) => { + let objectURL = URL.createObjectURL(myBlob); + image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch((error) => { + console.log('There has been a problem with your fetch operation: ' + error.message); +}); + +console.log ('All done!');</pre> + +<p>O navegador vai começar a executar o código, veja a primeira declaração <code>console.log()</code>(<code>Starting</code>) e a execute, e depois crie a variável <code>image</code>.</p> + +<p>Depois a segunda linha vai começar a ser executada começando com o bloco <code>fetch()</code>, mas desde que <code>fetch()</code> é executado assíncronamente sem bloquear nada, a execução do código continua mesmo depois do código promise, alcançando a última declaração <code>console.log()</code>(<code>All done!</code>) e imprimindo a no console.</p> + +<p>Uma vez que o bloco <code>fetch()</code> tenha terminado a sua execução e retornado seu resultado com os blocos <code>.then()</code>, nós finalmente veremos a segunda mensagem <code>console.log()</code> (<code>It worked :)</code>) appear. Então as mensagens aparecem nessa ordem:</p> + +<ul> + <li>Starting</li> + <li>All done!</li> + <li>It worked :)</li> +</ul> + +<p>Se isso te deixa confuso, então considere o exemplo a seguir:</p> + +<pre class="brush: js">console.log("registering click handler"); + +button.addEventListener('click', () => { + console.log("get click"); +}); + +console.log("all done");</pre> + +<p>Isso é bem similar no comportamento — a primeira e a terceira mensagens <code>console.log()</code> são mostradas imediatamente, mas a segunda está bloqueada até alguém clique no botão. O exemplo anterior funciona da mesma forma, exceto que no caso a segunda mensagem está bloqueada na promise pegando um recurso e depois o mostra na tela.</p> + +<p>Em um exemplo mais superficial, esse tipo de configuração poderia causar um problema — você não pode incluir um bloco async que retorna um resultado, que depois depende de um código síncrono. Você não pode garantir que a função async vai retornar antes que o navegador processou o bloco síncrono.</p> + +<p>Para ver isso em ação, tente fazer uma cópia local do <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">nosso exemplo</a>, e mudar o terceiro <code>console.log()</code> para o seguinte:</p> + +<pre class="brush: js">console.log ('Tudo Feito! ' + image.src + 'mostrada.');</pre> + +<p>Agora você deve ter um erro no seu console ao invés da terceira mensagem:</p> + +<pre><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">TypeError: image is undefined; can't access its "src" property</span></span></span></pre> + +<p>Isso acontece porque o navegador tenta executar o terceiro <code>console.log()</code> e o bloco <code>fetch()</code> não terminou de ser executado e não foi dado um valor para a variável <code>image</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>:Por razões de segurança, você não pode usar o <code>fetch()</code> com arquivos do seu sistema local (ou executar operações localmente); para executar o exemplo acima você teria que rodá-lo em um <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">servidor local</a>.</p> +</div> + +<h2 id="Aprendizado_ativo_faça_tudo_async!">Aprendizado ativo: faça tudo async!</h2> + +<p>Faça que o exemplo problemático de <code>fetch()</code> imprima três mensagens <code>console.log()</code> na tela na ordem desejada, você pode fazer a útima declaração <code>console.log()</code> assíncrona também. Isso pode ser feito colocando ela em outro bloco <code>.then()</code> encadeamo no final do segundo bloco, ou por simplesmente movê-lo para dentro do segundo bloco <code>then()</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync-fixed.html">find an answer here</a> (see it <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync-fixed.html">running live</a> also). You can also find a lot more information on promises in our <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a> guide, later on in the module.</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>In its most basic form, JavaScript is a synchronous, blocking, single-threaded language, in which only one operation can be in progress at a time. But web browsers define functions and APIs that allow us to register functions that should not be executed synchronously, and should instead be invoked asynchronously when some kind of event occurs (the passage of time, the user's interaction with the mouse, or the arrival of data over the network, for example). This means that you can let your code do several things at the same time without stopping or blocking your main thread.</p> + +<p>Whether we want to run code synchronously or asynchronously will depend on what we're trying to do.</p> + +<p>There are times when we want things to load and happen right away. For example when applying some user-defined styles to a webpage you'll want the styles to be applied as soon as possible.</p> + +<p>If we're running an operation that takes time however, like querying a database and using the results to populate templates, it is better to push this off the main thread and complete the task asynchronously. Over time, you'll learn when it makes more sense to choose an asynchronous technique over a synchronous one.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> |