<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ JavaScript - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ JavaScript - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 18 May 2026 10:23:15 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/javascript/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma promise a partir de uma função de callback em JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Adham El Banhawy Desenvolvedores de back-end enfrentam desafios o tempo todo ao criar aplicações ou testar código. Por ser um desenvolvedor relativamente novo e que está recém se familiarizando com esses desafios, nunca me deparei com um desafio ou inconveniência com mais frequência — ou mais memorável — ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-promise-a-partir-de-uma-funcao-de-callback-em-javascript/</link>
                <guid isPermaLink="false">670530e9c4cc5853cfe82a85</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Tue, 08 Oct 2024 13:34:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/10/1_7EYmjkeLQs8QXSLr_6iTMg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-make-a-promise-out-of-a-callback-function-in-javascript-d8ec35d1f981/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to make a Promise out of a Callback function in JavaScript</a>
      </p><p>Escrito por: Adham El Banhawy</p><p>Desenvolvedores de back-end enfrentam desafios o tempo todo ao criar aplicações ou testar código. Por ser um desenvolvedor relativamente novo e que está recém se familiarizando com esses desafios, nunca me deparei com um desafio ou inconveniência com mais frequência — ou mais memorável — do que quando usei <strong>funções de callback</strong>.</p><p>Não vou me aprofundar muito nos detalhes das <em>callbacks</em> e seus prós e contras nem nas alternativas a elas, como <em>promises</em> e <em>async/await</em>. Para uma explicação mais detalhada, você pode conferir <a href="https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee">este artigo</a> (em inglês) que as explica detalhadamente.</p><h3 id="o-inferno-das-callbacks"><strong>O inferno das <em>callbacks</em></strong></h3><p>As <em>callbacks</em> são uma funcionalidade útil do JavaScript que permite realizar chamadas assíncronas. Elas são funções que geralmente são passadas como um segundo parâmetro para outra função que está buscando dados ou realizando uma operação de E/S que leva tempo para completar.</p><p>Um exemplo disso é ao tentar fazer uma chamada de API usando o módulo <code>request</code> ou ao se conectar a um banco de dados do MongoDB. Se ambas as chamadas dependerem uma da outra ou se a informação que você está buscando for o URL do MongoDB ao qual você precisa se conectar, o que você pode fazer?</p><p>Nesse caso, é preciso aninhar essas chamadas uma dentro da outra:</p><pre><code>request.get(url, function(error, response, mongoUrl) {

  if(error) throw new Error("Erro ao buscar dados");

  MongoClient.connect(mongoUrl, function(error, client) {

    if(error) throw new Error("Erro de conexão com o MongoDB");

    console.log("Conectado com sucesso ao servidor");    
    const db = client.db("dbName");
    // Realizar alguma lógica da aplicação
    client.close();

  });

});
</code></pre><p>Certo... então, onde está o problema? Bem, por um lado, a legibilidade do código sofre com essa técnica.</p><p>Pode parecer aceitável no começo, quando a base de código é pequena, mas a escalabilidade disso não é das melhores, especialmente se você inserir mais camadas profundas nos <em>callbacks </em>aninhados.</p><p>Você acabará com muitos colchetes e chaves que confundirão você e outros desenvolvedores, não importando se o código está bem formatado ou não. Existe um site chamado <a href="http://callbackhell.com/">callbackhell</a> (em português, o "inferno das <em>callbacks</em>") que aborda essa questão específica.</p><p>Ouço alguns de vocês, incluindo meu eu passado ingênuo, me dizendo para envolver em uma função <code>async</code> e então <code>await</code> (em português, esperar) pela função de <em>callback</em>. Isso simplesmente não funciona.</p><p>Se houver qualquer bloco de código após a função que usa <em>callbacks</em>, aquele bloco de código será executado e <strong>NÃO</strong> <strong>esperará</strong> pela <em>callback</em>.</p><p>Aqui está o erro que cometi antes:</p><pre><code>var request = require('request');

// ERRADO

async function(){

  let joke;
  let url = "https://api.chucknorris.io/jokes/random"

  await request.get(url, function(error, response, data) {

    if(error) throw new Error("Erro ao buscar dados");

    let content = JSON.parse(data);
    joke = content.value;

  });

  console.log(joke); // undefined

};

// Errado

async function(){

  let joke;
  let url = "https://api.chucknorris.io/jokes/random"

  request.get(url, await function(error, response, data) {

    if(error) throw new Error("Erro ao buscar dados");

    let content = JSON.parse(data);
    joke = content.value;

  });

  console.log(joke); // undefined

};
</code></pre><p>Alguns desenvolvedores mais experientes podem dizer "Basta usar uma biblioteca diferente que use <em>promises</em> para fazer a mesma coisa, como o <a href="https://www.npmjs.com/package/axios">axios</a>, ou simplesmente usar o <a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Fetch_API">fetch</a>". Claro, eu poderia fazer isso nesse cenário, mas é apenas fugir do problema.</p><p>Além disso, esse é apenas um exemplo. Às vezes, você pode estar preso a usar uma biblioteca que não suporta <em>promises</em> sem alternativas, como ao usar kits de desenvolvimento de software (SDKs) para se comunicar com plataformas como a Amazon Web Services (AWS), o Twitter ou o Facebook.</p><p>Às vezes, até mesmo usar um <em>callback</em> para fazer uma chamada muito simples com uma E/S rápida ou uma operação de CRUD está bem, já que nenhuma outra lógica depende de seus resultados. Você, no entanto, pode estar restrito pelo ambiente de execução, como em uma <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction-function.html">função Lambda</a> (site em inglês) que mataria todos os processos uma vez que a <em>thread</em> principal terminasse, independentemente de qualquer chamada assíncrona que não tenha sido concluída.</p><h3 id="solu-o-1-f-cil-usar-o-m-dulo-util-do-node">Solução 1 (fácil): usar o módulo "util" do Node</h3><p>A solução é surpreendentemente simples. Mesmo se você estiver um pouco desconfortável com a ideia de <em>promises </em>no JavaScript, você vai adorar como pode resolver esse problema usando-as.</p><p>Como apontado por Erop e Robin, as versões a partir da versão 8 do Node suportam transformar funções de <em>callback</em> em <em>promises</em> usando o módulo interno <strong>util</strong>.</p><pre><code>const request = require('request');

const util = require('util');

const url = "https://api.chucknorris.io/jokes/random";

// Use o util para trasnformar em promise o método request

const getChuckNorrisFact = util.promisify(request);

// Use o novo método para chamar a API em um padrão moderno de then/catch

getChuckNorrisFact(url).then(data =&gt; {

   let content = JSON.parse(data.body);

   console.log('Piada: ', content.value);

}).catch(err =&gt; console.log('erro: ', err))
</code></pre><p>O código acima resolve o problema de maneira limpa usando o método <a href="https://nodejs.org/docs/latest-v8.x/api/util.html#util_util_promisify_original"><strong>util.promisify</strong></a><strong>,</strong> disponível na biblioteca principal do Node.</p><h3 id="solu-o-2-um-pouco-mais-complicada-transformar-a-callback-em-uma-promise">Solução 2 (um pouco mais complicada): transformar a callback em uma <em>promise</em></h3><p>Às vezes, usar as bibliotecas <code>request</code> e <code>util</code> não é possível, seja por causa de um ambiente/código legado ou por realizar as requisições a partir do navegador do lado do <em>client</em>. Você precisaria encapsular uma <em>promise</em> em torno de sua função de <em>callback</em>.</p><p>Vamos pegar o exemplo do Chuck Norris acima e transformá-lo em uma <em>promise</em>.</p><pre><code>var request = require('request');
let url = "https://api.chucknorris.io/jokes/random";

// Uma função que retorna uma promise para resolver os dados obtidos da API ou um erro
let getChuckNorrisFact = (url) =&gt; {
  return new Promise(
    (resolve, reject) =&gt; {
      request.get(url, function(error, response, data){
        if (error) reject(error);

let content = JSON.parse(data);
        let fact = content.value;
        resolve(fact);
      })
   }
 );
};

getChuckNorrisFact(url).then(
   fact =&gt; console.log(fact) // realmente exibe uma string
).catch(
   error =&gt; console.log(error)
);
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/10/ZXNYPRkv4mC2cHoq-4PIdoAx0WK-DyuUybzA.jpeg" class="kg-image" alt="ZXNYPRkv4mC2cHoq-4PIdoAx0WK-DyuUybzA" width="366" height="488" loading="lazy"><figcaption><em>Parece mágica</em></figcaption></figure><p>No código acima, coloquei a função <code>request</code> baseada em <em>callback</em> dentro de uma <em>promise</em> que a envolve <code>Promise((resolve, reject) =&gt; { //função de callback})</code>. Isso nos permite chamar a função <code>getChuckNorrisFact</code> como uma <em>promise</em> com os métodos <code>**.then()**</code> e <code>.catch()</code>. Quando <code>_getChuckNorrisFact_</code> é chamada, ela executa a requisição para a API e <strong>espera</strong> por uma declaração <code>resolve()</code> ou <code>reject()</code> para executar. Na função de <em>callback</em>, você simplesmente passa os dados recuperados para os métodos <em>resolve</em> ou <em>reject</em>.</p><p>Uma vez que os dados (nesse caso, um fato incrível sobre Chuck Norris) são obtidos e passados para o <em>resolve</em>, <code>getChuckNorrisFact</code> executa o método <code>then()</code>. Isso retornará o resultado que você pode <strong>utilizar dentro de uma função dentro do <code>then()</code></strong> para realizar a lógica desejada — que, nesse caso, é exibir o fato no console.</p><p>Você pode ler mais sobre isso na <a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Using_promises#Creating_a_Promise_around_an_old_callback_API">documentação da web da MDN</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Uma introdução aos testes unitários com o Jasmine ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Ahmed Bouchefra O Jasmine é a biblioteca do JS mais popular para testes unitários de aplicações para a web. Neste tutorial, projetado para iniciantes, apresentaremos um guia rápido e completo para testes com o Jasmine. Você será apresentado ao Jasmine, um framework de testes popular orientado a comportamentos ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/uma-introducao-aos-testes-unitarios-com-o-jasmine/</link>
                <guid isPermaLink="false">66a30c2f28ded7044a1fe1f2</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kris Lagerström ]]>
                </dc:creator>
                <pubDate>Sun, 22 Sep 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/5f9ca766740569d1a4ca76f2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/jasmine-unit-testing-tutorial-4e757c2cbf42/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">An Introduction to Jasmine Unit Testing</a>
      </p><p>Escrito por: Ahmed Bouchefra</p><p>O Jasmine é a biblioteca do JS mais popular para testes unitários de aplicações para a web. Neste tutorial, projetado para iniciantes, apresentaremos um guia rápido e completo para testes com o Jasmine.</p><p>Você será apresentado ao Jasmine, um <em>framework</em> de testes popular orientado a comportamentos para o JavaScript. Também veremos um exemplo prático simples de como escrever testes unitários com o Jasmine, que pode ajudá-lo a verificar facilmente se há <em>bugs</em> em seu código.</p><p>Em resumo, veremos como escrever suítes de teste, especificações e expectativas, além de como aplicar <em>matchers</em> (comparadores) integrados do Jasmine ou criar seus próprios <em>matchers</em> personalizados.</p><p>Também veremos como você pode agrupar suítes para organizar seus testes para bases de código mais complexas.</p><h3 id="apresentando-o-jasmine">Apresentando o Jasmine</h3><p>O <a href="http://jasmine.github.io/">Jasmine</a> é um <em>framework</em> de desenvolvimento orientado a comportamentos (em inglês, BDD ou <em>behavior-driven development)</em>. Com ele, você escreve testes antes de escrever o código real. Ele é muito popular para testes unitários de aplicações em JavaScript. Ele fornece utilitários que podem ser usados para executar testes automatizados para código síncrono e assíncrono.</p><p>O Jasmine tem muitos recursos:</p><ul><li>Ele é rápido, tem baixa sobrecarga e nenhuma dependência externa.</li><li>É uma biblioteca completa e oferece tudo o que você precisa para testar seu código.</li><li>Está disponível para Node e para o navegador.</li><li>Pode ser usado com outras linguagens, como Python e Ruby.</li><li>Não requer o DOM.</li><li>Fornece uma sintaxe limpa e fácil de entender e também uma API rica e direta.</li><li>Podemos usar linguagem natural para descrever os testes e os resultados esperados.</li></ul><p>O Jasmine é uma ferramenta de código aberto disponível sob a licença permissiva do MIT. No momento da redação deste artigo, a versão principal mais recente é a <em>Jasmine 3.0</em>, que fornece novos recursos e algumas mudanças significativas. A versão <em>2.99</em> do Jasmine fornecerá diferentes avisos de descontinuação para suítes que têm comportamento diferente na versão <em>3.0</em>, o que facilitará a migração dos desenvolvedores para a nova versão.</p><p>Você pode ler sobre os novos recursos e mudanças significativas <a href="https://github.com/jasmine/jasmine/blob/v3.0.0/release_notes/3.0.md">neste </a><a href="https://github.com/jasmine/jasmine/blob/v3.0.0/release_notes/3.0.md">documento</a>.</p><h3 id="usando-o-jasmine">Usando o Jasmine</h3><p>Você pode usar o Jasmine de várias maneiras diferentes:</p><ul><li>da maneira antiga, incluindo o núcleo do Jasmine e seus arquivos de teste usando uma tag <code>&lt;script&gt;</code>,</li><li>como uma ferramenta da CLI usando o Node.js,</li><li>como uma biblioteca no Node.js,</li><li>como parte de um sistema de <em>build</em>, como Gulp.js ou Grunt.js via <a href="https://github.com/gruntjs/grunt-contrib-jasmine">grunt-contrib-jasmine</a> e <a href="https://github.com/jasmine/gulp-jasmine-browser">gulp-jasmine-browser</a></li></ul><p>Você também pode usar o Jasmine para testar seu código em Python com <a href="https://github.com/jasmine/jasmine-py">jasmine-py</a>, que pode ser instalado a partir do PyPI usando o comando <code>pip install jasmine</code>. Este pacote contém um servidor para a web que serve e executa uma suíte do Jasmine para seu projeto e um script da CLI para executar testes e integrações contínuas.</p><p>O Jasmine também está disponível para projetos Ruby via <a href="https://github.com/jasmine/jasmine-gem">jasmine-gem</a>, que pode ser instalado adicionando <code>gem 'jasmine'</code> ao seu Gemfile e executando <code>bundle install</code>. Ele inclui um servidor para servir e executar testes, um script da CLI e também geradores para projetos Ruby on Rails.</p><p>Agora, vamos nos concentrar em como usar o Jasmine com JavaScript:</p><h3 id="usando-o-jasmine-standalone">Usando o Jasmine Standalone</h3><p>Comece baixando a versão mais recente do Jasmine na página de <a href="https://github.com/jasmine/jasmine/releases"><em>releases</em></a> (lançamentos).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/c1Ieo1kBD-F8mAKy1ZKYbc2IayEoMWHDL1eH.png" class="kg-image" alt="c1Ieo1kBD-F8mAKy1ZKYbc2IayEoMWHDL1eH" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/c1Ieo1kBD-F8mAKy1ZKYbc2IayEoMWHDL1eH.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/c1Ieo1kBD-F8mAKy1ZKYbc2IayEoMWHDL1eH.png 635w" width="635" height="253" loading="lazy"></figure><p>Em seguida, basta extrair o arquivo zip, de preferência dentro de uma pasta no projeto que você deseja testar.</p><p>A pasta conterá diversos arquivos e pastas padrão:</p><p><code>/src</code>: contém os arquivos de código-fonte que você deseja testar. Essa pasta pode ser excluída se você já tiver a pasta do seu projeto configurada. Ela também pode ser usada quando for apropriado para hospedar seu código-fonte.</p><p><code>/lib</code>: contém os arquivos principais do Jasmine.</p><p><code>/spec</code>: contém os testes que você vai escrever.</p><p><code>SpecRunner.html</code>: é um arquivo usado como um executor de testes. Você executa suas especificações simplesmente iniciando esse arquivo.</p><p>Este é o conteúdo de um arquivo <code>SpecRunner.html</code> padrão:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset="utf-8"&gt;
  &lt;title&gt;Jasmine Spec Runner v3.2.1&lt;/title&gt;

  &lt;link rel="shortcut icon" type="image/png" href="lib/jasmine-3.2.1/jasmine_favicon.png"&gt;
  &lt;link rel="stylesheet" href="lib/jasmine-3.2.1/jasmine.css"&gt;

  &lt;script src="lib/jasmine-3.2.1/jasmine.js"&gt;&lt;/script&gt;
  &lt;script src="lib/jasmine-3.2.1/jasmine-html.js"&gt;&lt;/script&gt;
  &lt;script src="lib/jasmine-3.2.1/boot.js"&gt;&lt;/script&gt;

  &lt;!-- include source files here... --&gt;
  &lt;script src="src/Player.js"&gt;&lt;/script&gt;
  &lt;script src="src/Song.js"&gt;&lt;/script&gt;

  &lt;!-- include spec files here... --&gt;
  &lt;script src="spec/SpecHelper.js"&gt;&lt;/script&gt;
  &lt;script src="spec/PlayerSpec.js"&gt;&lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>Lembre-se de que você precisa alterar os arquivos incluídos das pastas <code>/src</code> e <code>/spec</code> para conter seus arquivos de código-fonte e de teste reais.</p><h3 id="usando-o-jasmine-como-uma-biblioteca">Usando o Jasmine como uma biblioteca</h3><p>Você também pode usar o Jasmine como uma biblioteca em seu projeto. Por exemplo, o código a seguir importa e executa o Jasmine:</p><pre><code class="language-javascript">var Jasmine = require('jasmine');
var jasmine = new Jasmine();

jasmine.loadConfigFile('spec/support/jasmine.json');

jasmine.execute();
</code></pre><p>Primeiro, solicitamos/importamos o Jasmine e usamos o método <code>loadConfigFile()</code> para carregar o arquivo de configuração disponível no caminho <code>spec/support/jasmine.json</code> e, finalmente, executamos o Jasmine.</p><h3 id="usando-o-jasmine-via-cli">Usando o Jasmine via CLI</h3><p>Você também pode usar o Jasmine a partir da CLI (interface de linha de comando), o que permite executar facilmente os testes do Jasmine e, por padrão, gerar os resultados no terminal.</p><p>Seguiremos essa abordagem para executar nossos testes de exemplo neste guia, então, primeiro, execute o seguinte comando para instalar o Jasmine globalmente:</p><pre><code class="language-bash">npm install -g jasmine
</code></pre><blockquote><em>Você pode precisar executar <strong>sudo</strong> para instalar pacotes npm globalmente, dependendo da sua <a href="https://docs.npmjs.com/getting-started/fixing-npm-permissions">configuração do npm</a>.</em></blockquote><p>Agora, crie uma pasta para seu projeto e navegue para dentro dela:</p><pre><code class="language-bash">$ mkdir jasmine-project $ cd jasmine-project
</code></pre><p>Em seguida, execute o seguinte comando para inicializar seu projeto para o Jasmine:</p><p>O comando simplesmente cria uma pasta <code>spec</code> e um arquivo de configuração JSON. Esta é a saída do comando <code>dir</code>:</p><pre><code class="language-bash">.
└── spec
    └── support
        └── jasmine.json

2 directories, 1 file
</code></pre><p>Este é o conteúdo de um arquivo <code>jasmine.json</code> padrão:</p><pre><code class="language-js">{
  "spec_dir": "spec",
  "spec_files": [
    "**/*[sS]pec.js"
  ],
  "helpers": [
    "helpers/**/*.js"
  ],
  "stopSpecOnExpectationFailure": false,
  "random": true
}
</code></pre><ul><li><code>spec_dir</code>: especifica onde o Jasmine procura arquivos de teste.</li><li><code>spec_files</code>: especifica os padrões de arquivos de teste. Por padrão, todos os arquivos JS que terminam com as strings <strong>Spec</strong> ou <strong>spec</strong>.</li><li><code>helpers</code>: especifica onde o Jasmine procura arquivos auxiliares. Os arquivos auxiliares são executados antes das especificações e podem ser usados para definir <em>matchers</em> personalizados.</li><li><code>stopSpecOnExpectationFailure</code>: quando definido como <code>true</code>, interromperá imediatamente uma especificação na primeira falha de uma expectativa (pode ser usado como uma opção CLI via <code>--stop-on-failure</code>).</li><li><code>random</code>: quando definido como <code>true</code>, o Jasmine executará os casos de teste de modo pseudoaleatório (pode ser usado como uma opção da CLI via <code>--random</code>).</li></ul><p>Os arrays <code>spec_files</code> e <code>helpers</code> também podem conter padrões <a href="https://pt.wikipedia.org/wiki/Glob">Glob</a> (graças ao pacote <a href="https://github.com/isaacs/node-glob">node-glob</a>) para especificar caminhos de arquivo que são padrões que você normalmente usa para especificar um conjunto de arquivos ao trabalhar no Bash (por exemplo, <code>ls *.js</code>).</p><p>Se você não usar o local padrão para o arquivo de configuração <code>jasmine.json</code>, basta especificar o local personalizado por meio da opção <code>jasmine --config</code>.</p><p>Você pode encontrar mais opções da CLI na <a href="https://jasmine.github.io/setup/nodejs.html">documentação oficial</a>.</p><h3 id="entendendo-o-jasmine">Entendendo o Jasmine</h3><p>Nesta seção, aprenderemos sobre os elementos básicos dos testes do Jasmine, como suítes, especificações, expectativas, <em>matchers</em> e <em>spies</em> etc.</p><p>Na pasta do projeto, ao executar o comando para inicializar um novo módulo do Node, <code>npm init -y</code>, você criará um arquivo <code>package.json</code> com informações padrão:</p><pre><code class="language-js">{
  "name": "jasmine-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
</code></pre><p>Em seguida, crie um arquivo <code>index.js</code> e adicione o seguinte código:</p><pre><code class="language-js">function fibonacci(n){

    if (n === 1) {
        return [0, 1];
    }
    else {
        var s = fibonacci(n - 1);
        s.push(s[s.length - 1] + s[s.length - 2]);
        return s;
    }
}
function isPrime(num){
    for (let i = 2; i &lt; num; i++)
        if (num % i === 0) return false;
    return num !== 1 &amp;&amp; num !== 0;
}
function isEven(n) {
    return n % 2 == 0;
}
function isOdd(n) {
    return Math.abs(n % 2) == 1;
}

function toLowerCase(str){
    return str.toLowerCase();
}
function toUpperCase(str){
    return str.toUpperCase();
}
function contains(str, substring, fromIndex){
    return str.indexOf(substring, fromIndex) !== -1;
}
function repeat(str, n){
    return (new Array(n + 1)).join(str);
}

module.exports = {
    fibonacci: fibonacci,
    isPrime: isPrime,
    isEven: isEven,
    isOdd: isOdd,
    toLowerCase: toLowerCase,
    toUpperCase: toUpperCase,   
    contains: contains,
    repeat: repeat
};
</code></pre><h3 id="su-tes">Suítes</h3><p>Uma suíte agrupa um conjunto de especificações ou casos de teste. É usada para testar um comportamento específico do código em JavaScript que geralmente é encapsulado por um objeto/classe ou uma função. Ela é criada usando a função global do Jasmine <code>describe()</code>, que recebe dois parâmetros, o título da suíte de teste e uma função que implementa o código real da suíte de teste.</p><p>Vamos começar criando nossa primeira suíte de teste. Dentro da pasta <code>spec</code>, crie um arquivo <code>MyJSUtilitiesSpec.js</code> e adicione:</p><pre><code class="language-js">describe("MyJSUtilities", function() { /* ... */ });
</code></pre><p><em>MyJSUtilities</em> é o nome da suíte de teste de nível superior.</p><h4 id="como-agrupar-e-aninhar-su-tes">Como agrupar e aninhar suítes</h4><p>Para melhor organização e descrição precisa do nosso conjunto de testes, podemos aninhar suítes dentro da suíte de nível superior. Por exemplo, vamos adicionar duas suítes à suíte <em>MyJSUtilities</em>:</p><pre><code class="language-js">describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});
</code></pre><p>Dentro da suíte <em>Math Utils</em>, vamos também adicionar duas suítes aninhadas:</p><pre><code class="language-js">describe("Basic Math Utils", function() {   /* ... */ }); describe("Advanced Math Utils", function() {   /* ... */ });
</code></pre><p>Estamos agrupando testes relacionados em testes para <em>String Utils</em>, <em>Basic Math Utils</em> e <em>Advanced Math Utils</em> e aninhando-os dentro da suíte de nível superior <em>MyJSUtilities</em>. Isso comporá suas especificações como árvores semelhantes a uma estrutura de pastas.</p><p>A estrutura de aninhamento será mostrada no relatório, o que facilita a localização de testes com falha.</p><h4 id="como-excluir-su-tes">Como excluir suítes</h4><p>Você pode desabilitar temporariamente uma suíte usando a função <code>xdescribe()</code>. Ela tem a mesma assinatura (parâmetros) de uma função <code>describe()</code>, o que significa que você pode desabilitar rapidamente suas suítes existentes simplesmente adicionando um <code>x</code> à função.</p><p>As especificações dentro de uma função <code>xdescribe()</code> serão marcadas como pendentes e não serão executadas no relatório.</p><h3 id="especifica-es">Especificações</h3><p>Uma especificação declara um caso de teste que pertence a uma suíte de teste. Isso é feito chamando a função global do Jasmine <code>it()</code>, que recebe dois parâmetros: o título da especificação (que descreve a lógica que queremos testar) e uma função que implementa o caso de teste real.</p><p>Uma especificação pode conter uma ou mais expectativas. Cada expectativa é simplesmente uma asserção que pode retornar <code>true</code> ou <code>false</code>. Para que a especificação seja aprovada, todas as expectativas pertencentes à especificação devem ser <code>true</code>. Caso contrário, a especificação falha.</p><p>Dentro da nossa suíte <em>String Utils</em>, adicione estas especificações:</p><pre><code class="language-js">describe("String Utils", function() {  it("should be able to lower case a string",function() {    /*...*/  });  it("should be able to upper case a string",function() {    /*...*/  });  it("should be able to confirm if a string contains a substring",function() {    /*...*/  });  it("should be able repeat a string multiple times",function() {    /*...*/  });});
</code></pre><p>Dentro da nossa suíte <em>Basic Math Utils</em>, vamos adicionar algumas especificações:</p><pre><code class="language-js">describe("Basic Math Utils", function() {  it("should be able to tell if a number is even",function() {    /*...*/  });     it("should be able to tell if a number is odd",function() {    /*...*/  });     });
</code></pre><p>Para <em>Advanced Math Utils</em>, vamos adicionar as especificações:</p><pre><code class="language-js">describe("Advanced Math Utils", function() {  it("should be able to tell if a number is prime",function() {    /*...*/  });   it("should be able to calculate the fibonacci of a number",function() {    /*...*/  }); });
</code></pre><h4 id="como-excluir-especifica-es">Como excluir especificações</h4><p>Assim como as suítes, você também pode excluir especificações individuais usando a função <code>xit()</code>, que desabilita temporariamente a especificação <code>it()</code> e a marca como pendente.</p><h3 id="expectativas">Expectativas</h3><p>As expectativas são criadas usando a função <code>expect()</code> que recebe um valor chamado <strong>real</strong> (que pode ser valores, expressões, variáveis, funções, objetos etc.). As expectativas compõem a especificação e são usadas junto com funções <em>matcher</em> (via encadeamento) para definir o que o desenvolvedor espera que uma unidade específica de código execute.</p><p>Uma função <em>matcher</em> compara um valor <strong>real</strong> (passado para a função <code>expect()</code> com a qual está encadeada) e um valor <strong>esperado</strong> (passado diretamente como um parâmetro para o <em>matcher</em>) e retorna <strong>true</strong> ou <strong>false</strong>, o que <strong>passa</strong> ou <strong>falha</strong> a especificação.</p><p>Você pode encadear a função <code>expect()</code> com vários <em>matchers</em>. Para negar/inverter o resultado booleano de qualquer <em>matcher</em>, você pode usar a palavra-chave <code>not</code> antes de chamar o <em>matcher</em>.</p><p>Vamos implementar as especificações do nosso exemplo. Por enquanto, usaremos <code>expect()</code> com o <em>matcher </em><code>nothing()</code>, que faz parte dos <em>matchers</em> integrados que veremos um pouco mais tarde. Isso passará em todas as especificações, pois não esperamos nada neste momento.</p><pre><code class="language-js">describe("MyJSUtilities", function() {describe("&gt;String Utils", function() {  it("should be able to lower case a string",function() {    expect().nothing();  });  it("should be able to upper case a string",function() {    expect().nothing();  });  it("should be able to confirm if a string contains a substring",function() {    expect().nothing();  });  it("should be able repeat a string multiple times",function() {    expect().nothing();  });     });describe("Math Utils", function() { describe("Basic Math Utils", function() {  it("should be able to tell if a number is even",function() {    expect().nothing();  });     it("should be able to tell if a number is odd",function() {    expect().nothing();  });    }); describe("Advanced Math Utils", function() {  it("should be able to tell if a number is prime",function() {    expect().nothing();  });   it("should be able to calculate the fibonacci of a number",function() {    expect().nothing();  });     }); });});
</code></pre><p>Esta é uma captura de tela dos resultados neste ponto:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/jvFGz7IVrci3GpsfT520cJg1T9lK3puc8Fca.png" class="kg-image" alt="jvFGz7IVrci3GpsfT520cJg1T9lK3puc8Fca" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/jvFGz7IVrci3GpsfT520cJg1T9lK3puc8Fca.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/jvFGz7IVrci3GpsfT520cJg1T9lK3puc8Fca.png 652w" width="652" height="387" loading="lazy"><figcaption>Temos oito especificações aprovadas e zero falhas.</figcaption></figure><p>Você pode usar <em>matchers</em> integrados ou também criar seus próprios <em>matchers</em> personalizados para suas necessidades específicas.</p><h3 id="matchers-integrados"><em>Matchers</em> integrados</h3><p>O Jasmine fornece um rico conjunto de <em>matchers</em> integrados. Vamos ver alguns dos mais importantes:</p><ul><li><code>toBe()</code> para testar identidade,</li><li><code>toBeNull()</code> para testar <code>null</code>,</li><li><code>toBeUndefined()/toBeDefined()</code> para testar <code>undefined</code>/não <code>undefined</code>,</li><li><code>toBeNaN()</code> para testar NaN (Not A Number)</li><li><code>toEqual()</code> para testar igualdade,</li><li><code>toBeFalsy()/toBeTruthy()</code> para testar falsidade/veracidade etc.</li></ul><p>Você pode encontrar a lista completa de <em>matchers </em>na <a href="https://jasmine.github.io/api/edge/matchers.html">documentação</a>.</p><p>Vamos agora implementar nossas especificações com alguns desses <em>matchers</em> quando apropriado. Primeiro, importe as funções que estamos testando em nosso arquivo <code>MyJSUtilitiesSpec.js</code>:</p><pre><code>const utils = require("../index.js");
</code></pre><p>Em seguida, comece com a suíte <em>String Utils</em> e altere <code>expect().nothing()</code> com as expectativas apropriadas.</p><p>Por exemplo, para a primeira especificação, esperamos que o método <code>toLowerCase()</code> seja primeiro definido e, em segundo lugar, retorne uma string em minúsculas, ou seja:</p><pre><code class="language-js">it("should be able to lower case a string",function() {        expect(utils.toLowerCase).toBeDefined();        expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world");  });
</code></pre><p>Este é o código completo para a suíte:</p><pre><code class="language-js">describe("&gt;String Utils", function() {  it("should be able to lower case a string",function() {    expect(utils.toLowerCase).toBeDefined();    expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world");  });  it("should be able to upper case a string",function() {    expect(utils.toUpperCase).toBeDefined();    expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD");  });  it("should be able to confirm if a string contains a substring",function() {    expect(utils.contains).toBeDefined();    expect(utils.contains("hello world","hello",0)).toBeTruthy();  });  it("should be able repeat a string multiple times",function() {    expect(utils.repeat).toBeDefined();    expect(utils.repeat("hello", 3)).toEqual("hellohellohello");  });     });
</code></pre><h3 id="matchers-personalizados">Matchers personalizados</h3><p>O Jasmine fornece a capacidade de escrever <a href="https://jasmine.github.io/tutorials/custom_matcher.html"><em>matchers personalizados</em></a> para implementar asserções não cobertas pelos <em>matchers </em>integrados ou apenas para tornar os testes mais descritivos e legíveis.</p><p>Por exemplo, vamos pegar a seguinte especificação:</p><pre><code class="language-js">it("should be able to tell if a number is even",function() {    expect(utils.isEven).toBeDefined();    expect(utils.isEven(2)).toBeTruthy();    expect(utils.isEven(1)).toBeFalsy();  });
</code></pre><p>Vamos supor que o método <code>isEven()</code> não esteja implementado. Se executarmos os testes, receberemos mensagens como a seguinte captura de tela:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/dHjK8DH8lMJRdUzXj23GiUMTPJ75zOg9rtbe.png" class="kg-image" alt="dHjK8DH8lMJRdUzXj23GiUMTPJ75zOg9rtbe" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/dHjK8DH8lMJRdUzXj23GiUMTPJ75zOg9rtbe.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/dHjK8DH8lMJRdUzXj23GiUMTPJ75zOg9rtbe.png 637w" width="637" height="182" loading="lazy"></figure><p>A mensagem de falha que recebemos diz <em>Expected undefined to be defined</em>, o que não nos dá nenhuma pista do que está acontecendo. Então, vamos tornar essa mensagem mais significativa no contexto do nosso domínio de código (isso será mais útil para bases de código complexas). Para isso, vamos criar um <em>matcher</em> personalizado.</p><p>Criamos <em>matchers</em> personalizados usando o método <code>addMatchers()</code>, que recebe um objeto composto por uma ou várias propriedades que serão adicionadas como <em>matchers</em>. Cada propriedade deve fornecer uma função <em>factory</em> que recebe dois parâmetros: <code>util</code>, que possui um conjunto de funções utilitárias para os <em>matchers</em> usarem (consulte: <code><a href="https://github.com/pivotal/jasmine/blob/master/src/core/matchers/matchersUtil.js">MatchersUtil.js</a></code>) e <code>customEqualityTesters</code>, que precisa ser passado se <code>util.equals</code> for chamado, devendo retornar um objeto com uma função <code>compare</code>, que será chamada para verificar a expectativa.</p><p>Precisamos registrar o <em>matcher</em> personalizado antes de executar cada especificação usando o método <code>beforeEach()</code>:</p><pre><code class="language-js">describe("/Basic Math Utils", function () {beforeEach(function () {jasmine.addMatchers({hasEvenMethod:  function (util, customEqualityTesters) {return {compare:  function (actual, expected) {var  result  = { pass:  utils.isEven  !==  undefined };if (result.pass) {result.message  =  "Expected isEven() to be not defined."}else {result.message  =  "Expected isEven() to be defined."}return  result;}}}});});/*...*/});
</code></pre><p>Podemos então usar o <em>matcher </em>personalizado em vez de <code>expect(utils.isEven).toBeDefined()</code>:</p><pre><code class="language-js">expect().hasEvenMethod();
</code></pre><p>Isso nos dará uma mensagem de falha melhor:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/OulftEemEqJoqGYNoPhHY4v3ok1VE5LE0K05.png" class="kg-image" alt="OulftEemEqJoqGYNoPhHY4v3ok1VE5LE0K05" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/OulftEemEqJoqGYNoPhHY4v3ok1VE5LE0K05.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/OulftEemEqJoqGYNoPhHY4v3ok1VE5LE0K05.png 646w" width="646" height="169" loading="lazy"></figure><h3 id="usando-beforeeach-e-aftereach-">Usando beforeEach() e afterEach()</h3><p>Para inicializar e limpar suas especificações, o Jasmine fornece duas funções globais, <code>beforeEach()</code> e <code>afterEach()</code>:</p><ul><li>A função <code>beforeEach</code> é chamada uma vez antes de cada especificação na suíte onde é chamada.</li><li>A função <code>afterEach</code> é chamada uma vez após cada especificação na suíte onde é chamada.</li></ul><p>Por exemplo, se você precisar usar quaisquer variáveis em sua suíte de teste, pode simplesmente declará-las no início da função <code>describe()</code> e colocar qualquer código de inicialização ou instanciação dentro de uma função <code>beforeEach()</code>. Finalmente, você pode usar a função <code>afterEach()</code> para redefinir as variáveis após cada especificação, para que você possa ter testes unitários puros sem a necessidade de repetir o código de inicialização e limpeza para cada especificação.</p><p>A função <code>beforeEach()</code> também é perfeitamente combinada com muitas APIs do Jasmine, como o método <code>addMatchers()</code> para criar <em>matchers</em> personalizados ou também com a função <code>done()</code> para aguardar operações assíncronas antes de continuar o teste.</p><h3 id="falhando-um-teste">Falhando um teste</h3><p>Você pode forçar um teste a falhar usando o método global <code>fail()</code> disponível no Jasmine. Por exemplo:</p><pre><code class="language-js">it("should explicitly fail", function () { fail('Forced to fail'); });
</code></pre><p>Você deve receber o seguinte erro:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/A0qZ0VRL7KrP2Xu0cCsRUq6vW4SRcMwov6Mn.png" class="kg-image" alt="A0qZ0VRL7KrP2Xu0cCsRUq6vW4SRcMwov6Mn" width="347" height="63" loading="lazy"></figure><h3 id="testando-exce-es">Testando exceções</h3><p>Quando você está testando seu código unitariamente, erros e exceções podem ser lançados, então você pode precisar testar esses cenários. O Jasmine fornece os <em>matchers</em> <code>toThrow()</code> e <code>toThrowError()</code> para testar quando uma exceção é lançada ou para testar uma exceção específica, respectivamente.</p><p>Por exemplo, se tivermos uma função que lança uma exceção <code>TypeError</code>:</p><pre><code class="language-js">function throwsError() { throw new TypeError("A type error"); }
</code></pre><p>Você pode escrever uma especificação para testar se uma exceção é lançada:</p><pre><code>it('it should throw an exception', function () { expect(throwsError).toThrow(); });
</code></pre><p>Ou você também pode usar o teste para a exceção <code>TypeError</code> específica:</p><pre><code class="language-js">it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });
</code></pre><h3 id="entendendo-spies">Entendendo <em>spies</em></h3><p>Muitas vezes, os métodos dependem de outros métodos. Isso significa que, ao testar um método, você pode acabar testando suas dependências também. Isso não é recomendado em testes, ou seja, você precisa garantir que está testando a função pura, isolando o método e vendo como ele se comporta, dado um conjunto de entradas.</p><p>O Jasmine fornece <a href="http://jasmine.github.io/2.0/introduction.html#section-Spies"><em>spies</em></a> que podem ser usados para "espionar"/ouvir chamadas de método em objetos e relatar se um método é chamado e em qual contexto e argumentos.</p><p>O Jasmine fornece duas maneiras de espionar chamadas de método: usando os métodos <code>spyOn()</code> ou <code>createSpy()</code>.</p><p>Você pode usar <code>spyOn()</code> quando o método já existe no objeto. Caso contrário, você precisa usar <code>jasmine.createSpy()</code>, que retorna uma nova função.</p><p>Por padrão, um <em>spy</em> apenas relatará se uma chamada foi feita sem chamar a função espionada (ou seja, a função parará de ser executada), mas você pode alterar o comportamento padrão usando estes métodos:</p><ul><li><code>and.callThrough()</code>: chama a função original,</li><li><code>and.returnValue(value)</code>: retorna o valor especificado,</li><li><code>and.callFake(fn)</code>: chama a função falsa em vez da original,</li><li><code>and.throwError(err)</code>: lança um erro,</li><li><code>and.stub()</code>: redefine o comportamento de <em>stub </em>padrão.</li></ul><p>Você pode usar um <em>spy</em> para coletar estatísticas de tempo de execução na função espionada, por exemplo, se você quiser saber quantas vezes sua função foi chamada.</p><p>Digamos que queremos garantir que nosso método <code>toUpperCase()</code> esteja usando o método <code>String.toUpperCase()</code> integrado. Precisamos, simplesmente, espionar <code>String.toUpperCase()</code> usando:</p><pre><code class="language-js">it("should be able to upper case a string", function () { 
</code></pre><pre><code>var spytoUpperCase = spyOn(String.prototype, 'toUpperCase') 
</code></pre><pre><code>expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); expect(String.prototype.toUpperCase).toHaveBeenCalled(); expect(spytoUpperCase.calls.count()).toEqual(1); });
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/k-BN6V3GrUluGjMy3gtCMOAeae6wvu4CVu52.png" class="kg-image" alt="k-BN6V3GrUluGjMy3gtCMOAeae6wvu4CVu52" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/k-BN6V3GrUluGjMy3gtCMOAeae6wvu4CVu52.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/k-BN6V3GrUluGjMy3gtCMOAeae6wvu4CVu52.png 648w" width="648" height="217" loading="lazy"></figure><p>O teste falhou devido à segunda expectativa, pois <code>utils.toUpperCase("hello world")</code> retornou <code>undefined</code> em vez do <em>HELLO WORLD</em> esperado. Isso ocorre porque, como mencionamos, anteriormente, após criar o <em>spy</em> em <code>toUpperCase()</code>, o método não é executado. Precisamos mudar esse comportamento padrão chamando <code>callThrough()</code>:</p><blockquote><em>Observe que uma função <code>spy</code> substitui a função espionada por um stub por padrão. Se você precisar chamar a função original, pode adicionar <code>.and.callThrough()</code> ao seu objeto <code>spy</code>.</em></blockquote><pre><code>var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();
</code></pre><p>Agora, todas as expectativas passam.</p><p>Você também pode usar <code>and.callFake()</code> ou <code>and.returnValue()</code> para falsificar a função espionada ou apenas o valor de retorno se você não quiser chamar a função real:</p><pre><code>var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.returnValue("HELLO WORLD"); 
</code></pre><pre><code class="language-js">var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });
</code></pre><p>Agora, se acabarmos não usando o <code>String.toUpperCase()</code> integrado em nossa própria implementação de <code>utils.toUpperCase()</code>, obteremos estas falhas:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/z43QKVly7yBHOnKndLsZ6Id4roK-G0ut9ufK.png" class="kg-image" alt="z43QKVly7yBHOnKndLsZ6Id4roK-G0ut9ufK" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/z43QKVly7yBHOnKndLsZ6Id4roK-G0ut9ufK.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/z43QKVly7yBHOnKndLsZ6Id4roK-G0ut9ufK.png 644w" width="644" height="305" loading="lazy"></figure><p>As duas expectativas <code>expect(String.prototype.toUpperCase).toHaveBeenCalled()</code> <code>expect(spytoUpperCase.calls.count()).toEqual(1)</code> falharam.</p><h3 id="como-lidar-com-assincronia-no-jasmine">Como lidar com assincronia no Jasmine</h3><p>Se o código que você está testando contém operações assíncronas, você precisa de uma maneira de informar ao Jasmine quando as operações assíncronas forem concluídas.</p><p>Por padrão, o Jasmine espera que qualquer operação assíncrona, definida por uma <em>callback</em>, uma <em>promise</em> ou a palavra-chave <code>async</code>, seja concluída. Se o Jasmine encontrar uma <em>callback</em>, <em>promise</em> ou palavra-chave async em uma dessas funções: <code>beforeEach</code>, <code>afterEach</code>, <code>beforeAll</code>, <code>afterAll</code> e <code>it</code>, ele aguardará a conclusão da operação assíncrona antes de prosseguir para a próxima operação.</p><h3 id="usando-done-com-beforeeach-it-">Usando <code>done()</code> com <code>beforeEach()</code>/<code>it()</code> ..</h3><p>Vamos pegar nosso exemplo <code>simulateAsyncOp()</code>, que simula uma operação assíncrona usando <code>setTimeout()</code>. Em um cenário do mundo real, pode ser uma solicitação Ajax ou qualquer coisa semelhante que aconteça de maneira assíncrona:</p><pre><code class="language-js">function simulateAsyncOp(callback){ 
</code></pre><pre><code>setTimeout(function () { callback(); }, 2000); }
</code></pre><p>Para testar esta função, podemos usar a função <code>beforeEach()</code> com a <em>callback</em> especial <code>done()</code>. Nosso código precisa invocar <code>done()</code> para informar ao Jasmine que a operação assíncrona foi concluída:</p><pre><code class="language-js">describe("/Async Op", function () {var  asyncOpCompleted  =  false;beforeEach(function (done) {utils.simulateAsyncOp(function(){  asyncOpCompleted  =  true;  done();});});it("should be able to tell if the async call has completed", function () {  expect(asyncOpCompleted).toEqual(true);});});
</code></pre><p>Podemos notar rapidamente uma desvantagem desse método, então precisamos escrever nosso código para aceitar a <em>callback</em> <code>done()</code>. No nosso caso, não codificamos o método <code>done()</code> em nosso <code>simulateAsyncOp(fn)</code>, mas fornecemos um parâmetro de <em>callback</em> apenas para poder chamar <code>done()</code>.</p><h3 id="usando-as-promises">Usando as <em>promises</em></h3><p>Se você não quiser criar código que dependa de como você escreve seu teste, pode usar uma <em>promise</em> e chamar a <em>callback</em> <code>done()</code> quando a <em>promise</em> for resolvida. Ou melhor ainda, a partir do Jasmine 2.7+, se seu código retornar uma <code>Promise</code>, o Jasmine aguardará até que ela seja resolvida ou rejeitada antes de executar o próximo código.</p><h3 id="usando-async-await">Usando async/await</h3><p>O Jasmine 2.7+ suporta chamadas a <code>async</code> e <code>await</code> em especificações. Isso o libera de colocar asserções em um bloco <code>.then()</code> ou <code>.catch()</code>.</p><pre><code class="language-js">it("should work with async/await", async () =&gt; { let completed = false; completed = await utils.simulateAsyncOp(); expect(completed).toEqual(true); });
</code></pre><p>Esta é a implementação de <code>simulateAsyncOp</code>:</p><pre><code class="language-js">function simulateAsyncOp() { 
</code></pre><pre><code class="language-js">return new Promise(resolve =&gt; { setTimeout(() =&gt; { resolve(true); }, 1000); }); }
</code></pre><h3 id="usando-o-jasmine-clock">Usando o Jasmine Clock</h3><p>O Jasmine Clock é usado para testar código assíncrono que depende de funções de tempo, como <code>setTimeout()</code>, da mesma maneira que testamos código síncrono, simulando APIs baseadas em tempo com métodos personalizados. Desse modo, você pode executar as funções testadas sincronicamente controlando ou avançando manualmente o relógio.</p><p>Você pode instalar o Jasmine Clock chamando a função <code>jasmine.clock().install</code> em sua especificação ou suíte.</p><p>Depois de usar o relógio, você precisa desinstalá-lo para restaurar as funções originais.</p><p>Com o Jasmine Clock, você pode controlar as funções <code>setTimeout</code> ou <code>setInterval</code> do JavaScript avançando o relógio para avançar no tempo usando a função <code>jasmine.clock().tick</code>, que recebe o número de milissegundos que você pode mover.</p><p>Você também pode usar o Jasmine Clock para simular a data atual.</p><pre><code class="language-js">beforeEach(function () {jasmine.clock().install();});afterEach(function() {jasmine.clock().uninstall();});it("should call the asynchronous operation synchronously", function() {var  completed  =  false;utils.simulateAsyncOp(function(){completed  =  true;});expect(completed).toEqual(false);jasmine.clock().tick(1001);expect(completed).toEqual(true);});
</code></pre><p>Esta é a função <code>simulateAsyncOp</code>:</p><pre><code>function simulateAsyncOp(callback){ 
</code></pre><pre><code class="language-js">setTimeout(function () { callback(); }, 1000); }
</code></pre><blockquote><em>Caso você não tenha especificado um horário para a função <code>mockDate</code>, ela usará a data atual.</em></blockquote><h3 id="lidando-com-erros">Lidando com erros</h3><p>Se o seu código assíncrono falhar devido a algum erro, você vai querer que suas especificações falhem da maneira certa. A partir do Jasmine 2.6+, quaisquer erros não tratados são enviados para a especificação atualmente executada.</p><p>O Jasmine também fornece uma maneira que você pode usar se precisar falhar explicitamente em suas especificações:</p><ul><li>usando a callback <code>done()</code> com <code>beforeEach()</code> chamando o método <code>done.fail(err)</code>,</li><li>simplesmente passando um erro para a <em>callback </em><code>done(err)</code> (Jasmine 3+),</li><li>chamando o método <code>reject()</code> de uma <code>Promise</code>.</li></ul><h3 id="conclus-o">Conclusão</h3><p>Neste guia, apresentamos o Jasmine e vimos como começar a usá-lo para fazer testes unitários de seu código em JavaScript. Agradecemos pela leitura!</p><p>Este <a href="https://www.techiediaries.com/angular/jasmine-unit-testing/">artigo</a> foi publicado originalmente em <a href="https://www.techiediaries.com/">techiediaries</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ O que é uma função de callback em JavaScript? ]]>
                </title>
                <description>
                    <![CDATA[ Este artigo fornece uma breve introdução ao conceito e uso de funções de  callback na linguagem de programação JavaScript. Funções são objetos A primeira coisa que precisamos saber é que, em Javascript, as funções são objetos de primeira classe. Como tal, podemos trabalhar com elas da mesma maneira que ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/o-que-e-uma-funcao-de-callback-em-javascript/</link>
                <guid isPermaLink="false">66b4c31f050d6c03fd8b36ec</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Thu, 08 Aug 2024 13:29:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/08/5f9c9eb0740569d1a4ca3e8d.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/what-is-a-callback-function-in-javascript/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What is a Callback Function in JavaScript?</a>
      </p><p>Este artigo fornece uma breve introdução ao conceito e uso de funções de <em>callback</em> na linguagem de programação JavaScript.</p><h2 id="fun-es-s-o-objetos"><strong><strong><strong>Fun</strong>ções são objetos</strong></strong></h2><p>A primeira coisa que precisamos saber é que, em Javascript, as funções são objetos de primeira classe. Como tal, podemos trabalhar com elas da mesma maneira que trabalhamos com outros objetos. Podemos atribuí-los a variáveis e passá-los como argumentos para outras funções. Isso é importante, pois é a técnica que nos permite estender a funcionalidade de nossas aplicações.</p><h2 id="fun-es-de-callback"><strong><strong>Funções de <em>c<strong>allbac</strong></em><strong><em>k</em> </strong></strong></strong></h2><p>Uma <strong><strong>função de c</strong><strong><strong><strong>allback </strong></strong></strong></strong>é uma função que é passada <em>como um argumento</em> para outra função, para ser "chamada de volta" (em inglês, "called back") posteriormente. Uma função que aceita outras funções como argumentos é chamada <strong>de função de ordem superior</strong>, que contém a lógica para <em>quando</em> a função de <em>callback</em> é executada. É a combinação dessas duas que nos permite estender nossa funcionalidade.</p><p>Para ilustrar as funções de <em>callback</em>, vamos começar com um exemplo simples:</p><pre><code class="language-javascript">function criarFrase(frase, callback){ 
  var minhaFrase = "Como eu sempre digo, " + frase;
  callback(minhaFrase); // 2
}

function registrarFrase(frase){
  console.log(frase);
}

criarFrase("coma verduras!", registrarFrase); // 1

// Resultado no console: 
// Como eu sempre digo, coma verduras!</code></pre><p>No exemplo acima, <code>criarFrase</code> é a função de ordem superior, que aceita dois argumentos – sendo o segundo a função de <em>callback</em>. A função <code>registrarFrase</code> é usada para passar nossa função de <em>callback</em>. Quando executamos a função <code>criarFrase</code> <em><em>(1)</em></em>, perceba que não estamos <em>adicionando</em> parênteses a <code>registrarFrase</code> ao passá-la como argumento. Isso ocorre porque não queremos executar nossa função de <em>callback</em> imediatamente. Queremos apenas passar a definição da função para a função de ordem superior para que ela possa ser executada posteriormente.</p><p>Além disso, precisamos garantir que, se a função de <em>callback</em> que passamos espera argumentos, fornecemos esses argumentos ao executá-la <em><em>(2)</em></em>. No exemplo acima, na instrução <code>callback(minhaFrase);</code>, sabemos que <code>registrarFrase</code> espera que uma frase seja passada para ela.</p><p>Também podemos passar uma função anônima como <em>callback</em>. A chamada abaixo a <code>criarFrase</code> teria o mesmo resultado do exemplo acima:</p><pre><code class="language-javascript">criarFrase("coma verduras!", function(frase){ 
  console.log(frase); 
});</code></pre><p>Aliás, você não <em>precisa </em>usar a palavra "<em>callback</em>" como o nome do seu argumento, o JavaScript só precisa saber qual é o nome correto do argumento. Com base no exemplo acima, a função abaixo se comportará exatamente da mesma maneira.</p><pre><code class="language-javascript">function criarFrase(fraee, funcaoASerChamada) { 
  var minhaFrase = "Como eu sempre digo, " + frade;
  funcaoASerChamada(minhaFrase);
}</code></pre><h2 id="por-que-usar-fun-es-de-callback"><strong><strong>Por que usar funções de <em>c<strong>allback</strong></em><strong>?</strong></strong></strong></h2><p>Na maioria das vezes, criamos programas e aplicações que operam de <strong>modo síncrono</strong>. Em outras palavras, algumas de nossas operações são iniciadas somente após a conclusão das anteriores. Muitas vezes, quando solicitamos dados de outras fontes, como uma API externa, nem sempre sabemos <em>quando</em> nossos dados serão fornecidos de volta. Nesses casos, queremos aguardar a resposta, mas nem sempre queremos que toda a nossa aplicação aguarde enquanto nossos dados são buscados. Essas situações são onde as funções de <em>callback</em> são mais úteis.</p><p>Vamos dar uma olhada em um exemplo que simula uma solicitação para um servidor:</p><pre><code class="language-javascript">function requisicaoAoServidor(consulta, callback){
  setTimeout(function(){
    var resposta = consulta + "cheio!";
    callback(resposta);
  },5000);
}

function obterResultados(resultados){
  console.log("Resposta do servidor: " + resultados);
}

requisicaoAoServidor("O copo está meio ", obterResultados);

// Resultado no console após um atraso de 5 segundos:
// Resposta do servidor: O copo está meio cheio!</code></pre><p>No exemplo acima, fazemos uma simulação de solicitação para um servidor. Após 5 segundos, a resposta é modificada e, em seguida, nossa função de <em>callback</em> <code>obterResultados</code> é executada. Para ver isso em ação, você pode copiar/colar o código acima na ferramenta de desenvolvedor do seu navegador e executá-lo.</p><p>Além disso, se você já estiver familiarizado com <code>setTimeout</code>, saiba que já vem usando funções de <em>callback</em> há algum tempo. A função anônima passada no exemplo acima da chamada da função <code>setTimeout</code> também é uma função de <em>callback</em>! Assim, a função de <em>callback</em> original do exemplo é, de fato, executada por outra função de <em>callback</em>. Cuidado para não aninhar muitas <em>callbacks</em>. Evite isso, se possível, já que pode levar a algo chamado de "o inferno das <em>callbacks</em>" (em inglês, <em>callback hell</em>)! Como o próprio nome sugere, não é uma das melhores coisas com as quais desejaremos lidar.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ TypeOf em JavaScript – como verificar o tipo de uma variável ou objeto em JS ]]>
                </title>
                <description>
                    <![CDATA[ Tipos de dados e verificação de tipos são aspectos fundamentais em qualquer linguagem de programação. Muitas delas, como o Java, têm verificação de tipos estrita. Isso significa que, se uma variável é definida com um tipo específico, ela pode conter valores somente daquele tipo. O JavaScript, entretanto, é uma linguagem ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/typeof-em-javascript-como-verificar-o-tipo-de-uma-variavel-ou-objeto-em-js/</link>
                <guid isPermaLink="false">66aa497797bcd50408769d33</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Mon, 05 Aug 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-typeof-how-to-check-the-type-of-a-variable-or-object-in-js/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">JavaScript TypeOf – How to Check the Type of a Variable or Object in JS</a>
      </p><p>Tipos de dados e verificação de tipos são aspectos fundamentais em qualquer linguagem de programação. Muitas delas, como o Java, têm verificação de tipos estrita. Isso significa que, se uma variável é definida com um tipo específico, ela pode conter valores somente daquele tipo.</p><p>O JavaScript, entretanto, é uma linguagem fracamente (ou dinamicamente) tipada. Isso quer dizer que uma variável pode conter valores de qualquer tipo. O código em JavaScript pode ser executado assim:</p><pre><code class="language-js">let one = 1;
one = 'um';
one = true;
one = Boolean(true);
one = String('É possível');
</code></pre><p>Com isso em mente, é fundamental conhecer o tipo da variável em qualquer momento dado.</p><p>O tipo de uma variável é determinado pelo tipo do valor atribuído a ela. O JavaScript tem um operador especial, chamado <code>typeof</code>, que permite que você obtenha o tipo de qualquer valor.</p><p>Neste artigo, aprenderemos sobre como <code>typeof</code> é utilizado, juntamente com alguns cuidados que você deve ter.</p><h1 id="tipos-de-dados-em-javascript"><strong>Tipos de dados em <strong><strong>JavaScript</strong></strong></strong></h1><p>Vamos dar uma olhada rápida nos tipos de dados em JavaScript antes de entrarmos mais a fundo no operador <code>typeof</code>.</p><p>Em JavaScript, existem sete tipos primitivos. Um tipo primitivo é qualquer coisa que não seja um objeto. Esses tipos em JavaScript são:</p><ol><li>String</li><li>Number (número)</li><li>BigInt (número inteiro "grande")</li><li>Symbol (símbolo)</li><li>Boolean (booleano)</li><li>undefined (variável de tipo não definido - pois o valor ainda não foi definido)</li><li>null (tipo nulo)</li></ol><p>Todo o resto são objetos (em inglês, <code>object</code>) – incluindo <code>array</code> e <code>function</code>. Um objeto é uma coleção de pares chave-valor.</p><h1 id="o-operador-typeof-em-javascript"><strong>O operador <strong><strong><code>typeof</code> </strong></strong>em <strong><strong>JavaScript</strong></strong></strong></h1><p>O operador <code>typeof</code> recebe apenas um operando (é um operador unário). Ele avalia o tipo do operando e retorna o resultado como uma <em>string</em>. É assim que utilizamos o operador ao avaliar o tipo de um número, como, por exemplo, 007.</p><pre><code class="language-js">typeof 007;  // retorna 'number' - um número
</code></pre><p>Há uma sintaxe alternativa para o operador <code>typeof</code>, onde você pode usá-lo como uma <code>function</code>:</p><pre><code class="language-js">typeof(operando)
</code></pre><p>Essa sintaxe é útil quando você deseja avaliar uma expressão em vez de um valor único. Aqui temos um exemplo:</p><pre><code class="language-js">typeof(typeof 007); // retorna 'string'
</code></pre><p>No exemplo acima, a expressão <code>typeof 007</code> é avaliada com o tipo <code>number</code> e retorna a string 'number'. <code>typeof('number')</code>, portanto, é o que resulta em uma <code>'string'</code>.</p><p>Vamos ver outro exemplo para entender a importância dos parênteses com o operador <code>typeof</code>.</p><pre><code class="language-js">typeof(999-3223); // retorna "number"</code></pre><p>Se você omitir os parênteses, no entanto, ele retornará, <code>NaN</code> (<em>Not a Number</em> – em português, "não é um número"):</p><pre><code class="language-js">typeof 999-3223; // retorna NaN</code></pre><p>Isso ocorre porque, primeiramente, <code>typeof 999</code> resultará na string "number". A expressão <code>"number" - 32223</code> resultará em NaN, que é o que acontece quando você realiza uma operação de subtração entre uma <em>string </em>e um número.</p><h3 id="exemplos-de-uso-de-typeof-em-javascript"><strong>Exemplos de uso de <strong><strong><code>typeof</code> </strong></strong>em <strong><strong>JavaScript</strong></strong></strong></h3><p>O trecho de código abaixo mostra o resultado da verificação de tipo para vários valores usando o operador <code>typeof</code>.</p><pre><code class="language-js">typeof 0;  //'number'
typeof +0;  //'number'
typeof -0;  //'number'
typeof Math.sqrt(2);  //'number'
typeof Infinity;  //'number'
typeof NaN;  //'number', mesmo que seja Not a Number
typeof Number('100');  //'number', depois da coerção de sucesso para número
typeof Number('freeCodeCamp');  //'number', apesar do fato de não poder fazer a coerção da string para um número
typeof true;  //'boolean'
typeof false;  //'boolean'
typeof Boolean(0);  //'boolean'
typeof 12n;  //'bigint'
typeof '';  //'string'
typeof 'freeCodeCamp';  //'string'
typeof `freeCodeCamp is awesome`;  //'string'
typeof '100';  //'string'
typeof String(100); //'string'
typeof Symbol();  //'symbol'
typeof Symbol('freeCodeCamp');  //'symbol'
typeof {blog: 'freeCodeCamp', author: 'Tapas A'};  //'object';
typeof ['This', 'is', 101]; //'object'
typeof new Date();  //'object'
typeof Array(4);  //'object'
typeof new Boolean(true);  //'object'; 
typeof new Number(101);  //'object'; 
typeof new String('freeCodeCamp');  //'object';
typeof new Object;  //'object'
typeof alert;  //'function'
typeof function () {}; //'function'
typeof (() =&gt; {});  //'function' – é uma arrow function. Assim, é necessário o parênteses
typeof Math.sqrt;  //'function'
let a;
typeof a;  //'undefined'
typeof b;  //'undefined'
typeof undefined;  //'undefined'
typeof null;  //'object'</code></pre><p>A tabela abaixo mostra os valores de retorno da verificação de tipo com <code>typeof</code>:</p><!--kg-card-begin: html--><table data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bgimage="" data-darkreader-inline-bgcolor="" data-darkreader-inline-color="" style="border: 0px; box-sizing: inherit; margin: 0.5em 0px 2.5em; padding: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-weight: 400; font-stretch: inherit; line-height: inherit; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.6rem; vertical-align: top; border-spacing: 0px; border-collapse: collapse; background: radial-gradient(at left center, rgba(0, 0, 0, 0.2) 0px, transparent 75%) 0px center / 10px 100% no-repeat scroll, radial-gradient(at right center, rgba(0, 0, 0, 0.2) 0px, transparent 75%) 100% center / 10px 100% scroll rgb(255, 255, 255); color: rgb(10, 10, 35); display: inline-block; overflow-x: auto; max-width: 100%; width: auto; white-space: nowrap; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bgimage: radial-gradient(at left center, rgba(0, 0, 0, 0.2) 0px, rgba(0, 0, 0, 0) 75%),  radial-gradient(at right center, rgba(0, 0, 0, 0.2) 0px, rgba(0, 0, 0, 0) 75%); --darkreader-inline-bgcolor: #181a1b; --darkreader-inline-color: #dad7d2;"><thead data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><th data-darkreader-inline-color="" data-darkreader-inline-bgcolor="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.2rem; vertical-align: baseline; background-color: var(--gray10); color: var(--gray85); letter-spacing: 0.2px; text-align: left; text-transform: uppercase; --darkreader-inline-color: var(--darkreader-text--gray85, #e8e6e3); --darkreader-inline-bgcolor: var(--darkreader-bg--gray10, #181a1b);"><strong data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-color="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bold; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 12px; vertical-align: baseline; color: var(--gray85); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-color: var(--darkreader-text--gray85, #e8e6e3);">TIPO</strong></th><th data-darkreader-inline-color="" data-darkreader-inline-bgcolor="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.2rem; vertical-align: baseline; background-color: var(--gray10); color: var(--gray85); letter-spacing: 0.2px; text-align: center; text-transform: uppercase; --darkreader-inline-color: var(--darkreader-text--gray85, #e8e6e3); --darkreader-inline-bgcolor: var(--darkreader-bg--gray10, #181a1b);"><strong data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-color="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bold; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 12px; vertical-align: baseline; color: var(--gray85); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-color: var(--darkreader-text--gray85, #e8e6e3);">VALOR DE RETORNO DE TYPEOF</strong></th></tr></thead><tbody data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">String</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'string'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">Number</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'number'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">BigInt</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'bigint'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">Symbol</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'symbol'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">Boolean</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'boolean'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">undefined</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'undefined'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">Objeto function</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'function'</code></td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">null</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'object'</code>(ver abaixo!)</td></tr><tr data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px;"><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(90deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-size: 20px 100%; background-repeat: no-repeat; --darkreader-inline-bgimage: linear-gradient(90deg, #181a1b 50%, rgba(24, 26, 27, 0));">Qualquer outro objeto</td><td data-darkreader-inline-bgimage="" style="box-sizing: inherit; margin: 0px; padding: 6px 12px; border: 1px solid var(--gray10); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(270deg, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0)); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat; text-align: center; --darkreader-inline-bgimage: linear-gradient(270deg, #181a1b 50%, rgba(24, 26, 27, 0));"><code data-darkreader-inline-border-top="" data-darkreader-inline-border-right="" data-darkreader-inline-border-bottom="" data-darkreader-inline-border-left="" data-darkreader-inline-bg="" style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15); --darkreader-inline-border-top: 0px; --darkreader-inline-border-right: 0px; --darkreader-inline-border-bottom: 0px; --darkreader-inline-border-left: 0px; --darkreader-inline-bg: var(--darkreader-bg--gray15);">'object'</code></td></tr></tbody></table><!--kg-card-end: html--><h1 id="quest-es-importantes-com-typeof"><strong>Questões importantes com<strong><strong> <code>typeof</code></strong></strong></strong></h1><p>Há casos em que o operador <code>typeof</code> pode não retornar os tipos que se espera. Isso pode causar confusão e erros. Abaixo, veremos alguns desses casos:</p><h3 id="o-tipo-de-nan-number"><strong>O tipo de<strong><strong> NaN </strong></strong>é<strong><strong> number</strong></strong></strong></h3><pre><code class="language-js">typeof NaN;  //'number', mesmo que ele seja Not a Number (não é um número)</code></pre><p><code>typeof NaN</code> retorna <code>'number'</code>. Isso é estranho, já que não deveríamos detectar <code>NaN</code> usando <code>typeof</code>. Há maneiras melhores de se lidar com isso. Veremos essas maneiras em breve.</p><h3 id="o-tipo-de-null-object"><strong>O tipo de<strong><strong> <code>null</code> </strong></strong>é<strong><strong> <code>object</code></strong></strong></strong></h3><pre><code class="language-js">  typeof null;  //'object'
</code></pre><p>Em JavaScript, <code>typeof null</code> retorna <code>object</code>, o que dá a impressão errada de que <code>null</code> é um objeto, embora ele seja um valor primitivo.</p><p>O resultado de <code>typeof null</code> é, na verdade, um <em>bug</em> na linguagem. Houve uma tentativa de consertá-lo no passado, mas foi rejeitada devido a um problema de compatibilidade com versões anteriores.</p><h3 id="o-tipo-de-uma-vari-vel-n-o-declarada-undefined"><strong>O tipo de uma variável não declarada é <strong><strong><code>undefined</code></strong></strong></strong></h3><p>Antes da ES6, uma verificação de tipo de uma variável não declarada costumava resultar em <code>'undefined'</code>. Esse, no entanto, não é um modo à prova de erros de se lidar com isso.</p><p>Com a chegada da ES6, podemos declarar variáveis com escopo de bloco com as palavras-chave <code>let</code> ou <code>const</code>. Se você as utilizar com o operador <code>typeof</code> antes de elas serem inicializadas, verá um <code>ReferenceError</code> (em português, "erro de referência").</p><pre><code class="language-js"> typeof cat; // ReferenceError
 let cat = 'brownie'; </code></pre><h3 id="o-tipo-de-uma-fun-o-construtora-object"><strong>O tipo de uma função <strong><strong>constru</strong></strong>tora é <strong><strong><code>object</code></strong></strong></strong></h3><p>Todas as funções construtoras, com exceção do construtor de <code>Function</code>, sempre serão do tipo 'object'.</p><pre><code class="language-js">typeof new String('freeCodeCamp'); //'object'</code></pre><p>Isso pode causar uma certa confusão, já que esperamos que elas sejam do tipo de fato (no exemplo acima, do tipo <code>string</code>).</p><h3 id="o-tipo-de-um-array-object"><strong>O tipo de um<strong><strong> </strong></strong><em>a<strong><strong>rray</strong></strong></em><strong><strong> </strong></strong>é<strong><strong> <code>object</code></strong></strong></strong></h3><p>Embora isso esteja tecnicamente correto, pode desapontar bastante. Queremos diferenciar entre <em>arrays</em> e objetos, mesmo quando um <em>array</em>, tecnicamente, seja um objeto em JavaScript.</p><pre><code class="language-js">typeof Array(4);  //'object'</code></pre><p>Felizmente, há maneiras de se detectar um <em>array</em> corretamente. Veremos isso em breve.</p><h1 id="para-al-m-de-typeof-uma-verifica-o-de-tipos-melhor"><strong>Para além de<strong><strong> <code>typeof</code> – </strong></strong>uma verificação de tipos melhor</strong></h1><p>Agora que vimos algumas das limitações do operador <code>typeof</code>, vejamos como consertá-las para termos uma verificação de tipos melhor.</p><h3 id="como-detectar-nan"><strong>Como detectar <strong><strong>NaN</strong></strong></strong></h3><p>Em JavaScript, NaN é um valor especial. O valor NaN representa o resultado de uma expressão aritmética que não pode, de fato, ser representada. Por exemplo,</p><pre><code class="language-js">let result = 0/0;
console.log(result);  // retorna NaN
</code></pre><p>Além disso, se realizarmos qualquer operação aritmética com <code>NaN</code>, o resultado sempre será <code>NaN</code>.</p><pre><code class="language-js">console.log(NaN + 3); // retorna NaN
</code></pre><p>A verificação de tipo de NaN usando o operador <code>typeof</code> não ajuda muito, pois ela retorna o tipo como <code>'number'</code>. O JavaScript tem uma função global chamada <code>isNaN()</code> para detectar se um resultado é NaN.</p><pre><code class="language-js">isNaN(0/0); // retorna true
</code></pre><p>Porém, também temos um problema aqui.</p><pre><code class="language-js">isNaN(undefined); // retorna true para 'undefined'
</code></pre><p>Na ES6, o método <code>isNaN()</code> é adicionado ao objeto global <code>Number</code>. Esse método é muito mais confiável, sendo, portanto, o preferido.</p><pre><code class="language-js">Number.isNaN(0/0); // retorna true
Number.isNaN(undefined); // retorna false
</code></pre><p>Outro aspecto interessante de <code>NaN</code> é o fato de ser o único valor em JavaScript que nunca é igual a qualquer outro valor, incluindo ele mesmo. Então, há uma outra maneira de detectar NaN em ambientes onde não há suporte para a ES6:</p><pre><code class="language-js">function isNaN (input) {
  return input !== input;
}
</code></pre><h3 id="como-detectar-null-em-javascript"><strong>Como detectar <strong><strong>null </strong></strong>em <strong><strong>JavaScript</strong></strong></strong></h3><p>Como vimos anteriormente, detectar null usando o operador <code>typeof</code> é confuso. A maneira preferida de se verificar se algo é <code>null</code> é usando o operador de igualdade estrita (<code>===</code>).</p><pre><code class="language-js">function isNull(input) {
 return input === null;
}
</code></pre><p>Certifique-se de não usar <code>==</code> por engano. Se usar <code>==</code> no lugar de <code>===</code>, você poderá ter como resultado uma detecção de tipo enganadora.</p><h3 id="como-detectar-um-array-em-javascript"><strong>Como detectar um <em>a<strong><strong>rray</strong></strong></em><strong><strong> </strong></strong>em<strong><strong> JavaScript</strong></strong></strong></h3><p>A partir da ES6, podemos detectar um <em>array </em>usando o método <code>Array.isArray</code>.</p><pre><code class="language-js">Array.isArray([]); // retorna true
Array.isArray({}); // retorna false
</code></pre><p>Antes da ES6, poderíamos usar o operador <code>instanceof</code> para determinar se algo era um <em>array</em>:</p><pre><code class="language-js">function isArray(input) {
  return input instanceof Array;
}
</code></pre><h1 id="uma-solu-o-gen-rica-para-a-verifica-o-de-tipos-em-javascript"><strong>Uma solução genérica para a verificação de tipos em<strong><strong> JavaScript</strong></strong></strong></h1><p>Existe uma forma de criarmos uma solução genérica para a verificação de tipos. Dê uma olhada no método <code>Object.prototype.toString</code>. Ele é muito poderoso e extremamente útil para se escrever um método utilitário para a verificação de tipos.</p><p>Quando <code>Object.prototype.toString</code> é chamado usando <code>call()</code> ou <code>apply()</code>, ele retorna o tipo do objeto no formato <code>[object Tipo Correspondente]</code>. A parte do <code>Tipo Correspondente</code> no valor de retorno é o tipo verdadeiro.</p><p>Vamos ver como isso funciona com alguns exemplos:</p><pre><code class="language-js">// retorna '[object Array]'
Object.prototype.toString.call([]); 

// retorna '[object Date]'
Object.prototype.toString.call(new Date()); 

// retorna '[object String]'
Object.prototype.toString.call(new String('freeCodeCamp'));

// retorna '[object Boolean]'
Object.prototype.toString.call(new Boolean(true));

// retorna '[object Null]'
Object.prototype.toString.call(null);
</code></pre><p>Isso quer dizer que, se simplesmente pegarmos a <em>string </em>de retorno e removermos a parte do <code>object</code>, teremos o tipo de fato. Aqui, vemos uma tentativa de se fazer isso:</p><pre><code class="language-js">function conferirTipo(valor) {
  const valor_de_retorno = Object.prototype.toString.call(valor);
  // também podemos usar uma regex para isso...
  const tipo = valor_de_retorno.substring(
           valor_de_retorno.indexOf(" ") + 1, 
           valor_de_retorno.indexOf("]"));

  return tipo.toLowerCase();
}
</code></pre><p>Agora, podemos usar a função <code>conferirTipo</code> para detectar os tipos:</p><pre><code class="language-js">conferirTipo([]); // 'array'
conferirTipo(new Date()); // 'date'
conferirTipo(new String('freeCodeCamp')); // 'string'
conferirTipo(new Boolean(true)); // 'boolean'
conferirTipo(null); // 'null'
</code></pre><h1 id="em-resumo"><strong>Em resumo</strong></h1><p>Para resumir o que aprendemos neste artigo:</p><ul><li>A verificação de tipos em JavaScript não é tão estrita como em outras linguagens de programação.</li><li>Use o operador <code>typeof</code> para a detecção de tipos.</li><li>Existem duas sintaxes para o operador <code>typeof</code>: <code>typeof</code> e <code>typeof(expressão)</code>.</li><li>O resultado de um operador <code>typeof</code> pode, por vezes, ser enganoso. Precisamos confiar em outros métodos disponíveis (<code>Number.isNaN</code>, &nbsp;<code>Array.isArray</code>, entre outros) nesses casos.</li><li>Podemos usar <code>Object.prototype.toString</code> para criar um método de detecção de tipos genérico.</li></ul><h1 id="antes-de-terminar-"><strong>Antes de terminar<strong><strong>...</strong></strong></strong></h1><p>Obrigado pela leitura até aqui! Conecte-se com o autor do texto pelo <a href="https://twitter.com/tapasadhikary">Twitter</a> se quiser fazer comentários.</p><p>Você também pode gostar os seguintes artigos (em inglês):</p><ul><li><a href="https://blog.greenroots.info/javascript-undefined-and-null-lets-talk-about-it-one-last-time-ckh64kmz807v848s15kdkg3dd">JavaScript undefined and null: Let's talk about it one last time!</a></li><li><a href="https://blog.greenroots.info/javascript-equality-comparison-with-and-objectis-ckdpt2ryk01vel9s186ft8cwl">JavaScript: Equality comparison with ==, === and Object.is</a></li><li><a href="https://www.freecodecamp.org/news/javascript-this-keyword-binding-rules/">The JavaScript `this` Keyword + 5 Key Binding Rules Explained for JS Beginners</a></li></ul><p>Por enquanto, é só. Até o próximo artigo. Cuide-se bem e bons estudos. 😉</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Evento onclick do JavaScript explicado ]]>
                </title>
                <description>
                    <![CDATA[ O evento onclick no JavaScript permite que você, o programador, execute uma função quando se clica em um elemento. Exemplo de onclick com um botão <button onclick="minhaFuncao()">Clique aqui</button> <script>   function minhaFuncao() {     alert('Alguém clicou no botão!');   } </script> No exemplo simples acima, ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/evento-onclick-do-javascript-explicado/</link>
                <guid isPermaLink="false">66ab83a697bcd50408769d40</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Thu, 01 Aug 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/08/5f9c9eb2740569d1a4ca3e93.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-onclick-event-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">JavaScript Onclick Event Explained</a>
      </p><p>O evento <code>onclick</code> no JavaScript permite que você, o programador, execute uma função quando se clica em um elemento.</p><h2 id="exemplo-de-onclick-com-um-bot-o"><strong>Exemplo de onclick com um botão</strong></h2><pre><code class="language-javascript">&lt;button onclick="minhaFuncao()"&gt;Clique aqui&lt;/button&gt;

&lt;script&gt;
  function minhaFuncao() {
    alert('Alguém clicou no botão!');
  }
&lt;/script&gt;</code></pre><p>No exemplo simples acima, quando um usuário clica no botão, verá um alerta no navegador dizendo <code>Alguém clicou no botão!</code>.</p><h2 id="adicionando-o-onclick-dinamicamente"><strong>Adicionando o onclick dinamicamente</strong></h2><p>O evento <code>onclick</code> também pode ser adicionado de modo programático a qualquer elemento usando o código do exemplo a seguir:</p><pre><code class="language-javascript">&lt;p id="foo"&gt;Clique neste elemento.&lt;/p&gt;

&lt;script&gt;
  var p = document.getElementById("foo"); // Encontre o elemento de parágrado na página
  p.onclick = mostrarAlerta; // Adicione a função de onclick ao elemento
    
  function mostrarAlerta(event) {
    alert("Evento do onclick acionado!");
  }
&lt;/script&gt;</code></pre><h3 id="observa-o"><strong><strong>Observação</strong></strong></h3><p>É importante observar que, ao usar o <code>onclick</code>, podemos adicionar apenas uma função/um evento de "escuta" (do inglês, <em>listener</em>). Se quiser adicionar mais de uma, use <code>addEventListener()</code>, que é o modo preferencial de se adicionar eventos desse tipo.</p><p>No exemplo acima, quando um usuário clica no elemento de parágrafo <code>p</code> , no html, ele verá um alerta dizendo <code>Evento do onclick acionado!</code>.</p><h2 id="evitando-a-a-o-padr-o"><strong>Evitando a ação padrão</strong></h2><p>No entanto, se adicionarmos <code>onclick</code> a links (elemento de âncora, a tag <code>a</code> no HTML), pode ser que desejemos evitar que a ação padrão ocorra:</p><pre><code class="language-javascript">&lt;a href="https://guide.freecodecamp.org" onclick="meuAlerta()"&gt;Guias&lt;/a&gt;

&lt;script&gt;
  function meuAlerta(event) {
    event.preventDefault();
    alert("Alguém clicou no link, mas a página não foi aberta.");
  }
&lt;/script&gt;</code></pre><p>No exemplo acima, evitamos o comportamento padrão de um elemento <code>a</code> (que é o de abrir o link) usando <code>event.preventDefault()</code> dentro da função de <em>callback</em> associada a <code>onclick</code>.</p><p><a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Element/click_event">MDN</a></p><h3 id="outros-recursos"><strong>Outros recursos</strong></h3><p><a href="https://api.jquery.com/on/" rel="nofollow">Associando o manipulador de eventos .on() no jQuery</a> (em inglês)</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como implantar uma aplicação com MERN no Heroku usando o MongoDB Atlas ]]>
                </title>
                <description>
                    <![CDATA[ Introdução ao MERN Neste artigo, construiremos e implantaremos uma aplicação criada com a stack  MERN no Heroku. MERN, que significa MongoDB, Express, React e Node.js, é uma stack  (literalmente, em português, pilha – mas que podemos traduzir como "conjunto de tecnologias") popular usada na construção de aplicações para ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-implantar-uma-aplicacao-com-mern-no-heroku-usando-o-mongodb-atlas/</link>
                <guid isPermaLink="false">652d1efab73e2e03f70cea51</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Renato Almeida ]]>
                </dc:creator>
                <pubDate>Wed, 03 Jul 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_qgxaya.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/deploying-a-mern-application-using-mongodb-atlas-to-heroku/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Deploy a MERN Application to Heroku Using MongoDB Atlas</a>
      </p><h2 id="introdu-o-ao-mern">Introdução ao MERN</h2><p>Neste artigo, construiremos e implantaremos uma aplicação criada com a <em>stack</em> MERN no Heroku.</p><p>MERN, que significa MongoDB, Express, React e Node.js, é uma <em>stack</em> (literalmente, em português, pilha – mas que podemos traduzir como "conjunto de tecnologias") popular usada na construção de aplicações para a web. Ela envolve trabalho de <em>front-end</em> (com React), trabalho de <em>back-end</em> (com Express e NodeJS) e um banco de dados (com MongoDB).</p><p>O <a href="https://www.heroku.com/">Heroku</a>, por outro lado, é uma plataforma como serviço (PaaS) que permite aos desenvolvedores criar, executar e operar aplicações inteiramente na nuvem.</p><blockquote>Nota da tradução: até pouco tempo atrás, o Heroku dispunha de um espaço gratuito para essas implementações. Hoje em dia, mesmo a camada mais básica da plataforma vem com um custo.</blockquote><p>Para o banco de dados, usaremos o MongoDB Atlas, que é um serviço global de banco de dados em nuvem para aplicações modernas. É mais seguro do que ter o MongoDB instalado localmente em nosso servidor e também nos dá espaço para mais recursos em nossos servidores.</p><p>Para o <em>front-end</em>, construiremos uma aplicação em React simples, que faz solicitações POST a uma API para adicionar um usuário, também podendo fazer solicitações GET para obter todos os usuários.</p><p><em>Você pode pular para qualquer etapa com o índice listado abaixo.</em></p><h2 id="-ndice">Índice</h2><ul><li>Introdução ao MERN</li><li>Vamos começar a criar</li><li>Construindo a aplicação em React</li><li>Criando o <em>back-end</em></li><li>Conectando o banco de dados do MongoDB Atlas</li><li>Chamando APIs no <em>front-end</em></li><li>Implantando no Heroku</li><li>Criando uma aplicação no Heroku</li><li>Configurando o <em>package.json</em></li><li>Resumo</li></ul><h2 id="vamos-come-ar-a-criar">Vamos começar a criar</h2><h3 id="construindo-a-aplica-o-em-react">Construindo a aplicação em React</h3><p><strong>Nota</strong>: antes de começarmos nosso projeto, o <code>node</code> deve estar instalado em seu computador. O <code>node</code> também nos fornece o <code>npm</code>, que é usado para instalar pacotes.</p><h3 id="instalando-o-create-react-app">Instalando o create-react-app</h3><p>O <code>create-react-app</code> é usado para criar uma aplicação inicial em React.</p><blockquote>Nota da tradução: mais recentemente, surgiram alternativas ao <code>create-react-app</code> que consomem menos espaço e são mais práticas para a criação de aplicações em React, como o <a href="https://vitejs.dev/">Vite</a>. O <code>create-react-app</code>, no entanto, segue sendo uma boa alternativa em termos didáticos para quem está começando a aprender.</blockquote><p>Se você não tiver o <code>create-react-app</code> instalado, digite o seguinte na linha de comando:</p><pre><code class="language-shell">npm i create-react-app -g</code></pre><p>O parâmetro <code>-g</code> instala o pacote globalmente.</p><h3 id="criando-o-diret-rio-do-projeto">Criando o diretório do projeto</h3><pre><code class="language-shell">create-react-app my-project
cd my-project</code></pre><p>O primeiro comando acima cria um diretório "my-project" e instala as dependências que serão usadas na aplicação inicial em React. Após terminar a instalação, o segundo comando muda para o diretório do projeto.</p><h3 id="iniciando-a-aplica-o-e-fazendo-as-edi-es-necess-rias">Iniciando a aplicação e fazendo as edições necessárias</h3><pre><code class="language-shell">npm start</code></pre><p>O comando acima inicia a aplicação React, que fornece um URL onde você visualiza o projeto. Você pode, então, fazer as edições necessárias, como alterar imagens ou texto.</p><h3 id="instalando-o-axios">Instalando o axios</h3><pre><code class="language-shell">npm i axios --save</code></pre><p>O <code>axios</code> é uma biblioteca do JavaScript usada para facilitar requisições HTTP. Ele será usado para enviar requisições do <em>front-end</em> (React) para as APIs fornecidas pelo <em>back-end</em>.</p><h3 id="criando-o-back-end">Criando o <em>back-end</em></h3><p>O <em>back-end</em> gerencia as APIs, lida com requisições e também se conecta ao banco de dados.</p><h3 id="instalando-os-pacotes-de-back-end">Instalando os pacotes de <em>back-end</em></h3><pre><code class="language-shell">npm i express cors mongoose body-parser --save</code></pre><ol><li><code>express</code>: "O Express é uma infraestrutura para aplicações da web em Node.js mínima e flexível, que fornece um conjunto robusto de recursos para essas aplicações para a web" – <a href="http://expressjs.com/">documentação do Express</a> (em inglês)</li><li><code>cors</code>: "O CORS é um pacote do Node.js para fornecer um <em>middleware</em> para Connect/Express que pode ser usado para habilitar o CORS com várias opções" – <a href="https://www.npmjs.com/package/cors">documentação do CORS</a> (em inglês)</li><li><code>mongoose</code>: "O Mongoose é uma ferramenta de modelagem de objetos para MongoDB projetada para funcionar em um ambiente assíncrono. O Mongoose suporta <em>promises</em> e funções de <em>callback</em> (retornos de chamada)" – <a href="https://www.npmjs.com/package/mongoose">documentação do Mongoose</a></li><li><code>body-parser</code>: "O <em>middleware</em> de análise (e transformação dos dados) do <em>body</em> para o Node.js." – <a href="https://www.npmjs.com/package/body-parser">documentação do body-parser</a> (em inglês)</li></ol><blockquote>Nota da tradução: <code>body-parser</code> foi descontinuado. A análise e a transformação dos dados, agora, pode ser feita diretamente pelo Express.</blockquote><h3 id="criando-a-pasta-de-back-end">Criando a pasta de <em>back-end</em></h3><pre><code class="language-shell">mkdir backend
cd backend</code></pre><h3 id="configurando-o-back-end">Configurando <em>o back-end</em></h3><p><strong>Criando um ponto de entrada (<em>entry point</em>)</strong> <code>server.js</code></p><p>Primeiro, crie um arquivo <code>server.js</code>, que será o ponto de entrada para o <em>back-end</em>.</p><pre><code class="language-shell">touch server.js</code></pre><p>No arquivo <code>server.js</code>, digite o seguinte:</p><pre><code class="language-js">const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require('path')
const app = express();
require('./database');
-----
app.use(bodyParser.json());
app.use(cors());
-----
// API
const users = require('/api/users');
app.use('/api/users', users);
-----
app.use(express.static(path.join(__dirname, '../build')))
app.get('*', (req, res) =&gt; {
    res.sendFile(path.join(__dirname, '../build'))
})
-----
const port = process.env.PORT || 5000;
app.listen(port, () =&gt; {
    console.log(`Server started on port ${port}`);
});</code></pre><p><code>express.static</code> fornece arquivos estáticos que são aqueles construídos quando <code>npm run build</code> é executado em um projeto do React. Lembre-se de que o arquivo compilado está na pasta <code>build</code>.</p><p>A partir da nossa configuração, qualquer requisição enviada para <code>/api/users</code> será enviada para a API <code>users</code> que estamos prestes a configurar.</p><p><strong>Configurando a API </strong><code>users</code></p><pre><code class="language-shell">mkdir api
touch api/users.js</code></pre><p>No arquivo <code>api/users.js</code>, adicione o seguinte:</p><pre><code class="language-js">const express = require('express');
const router = express.Router()
-----
const User = require('../models/User');
-----
router.get('/', (req, res) =&gt; {
    User.find()
        .then(users =&gt; res.json(users))
        .catch(err =&gt; console.log(err))
})
-----
router.post('/', (req, res) =&gt; {
    const { name, email } = req.body;
    const newUser = new User({
        name: name, email: email
    })
    newUser.save()
        .then(() =&gt; res.json({
            message: "Created account successfully"
        }))
        .catch(err =&gt; res.status(400).json({
            "error": err,
            "message": "Error creating account"
        }))
})
module.exports = router </code></pre><p>No código acima, criamos um manipulador de requisições GET e POST, que busca todos os usuários e os publica. Buscar e adicionar um usuário ao banco de dados é auxiliado pelo modelo <code>User</code> que criaremos.</p><p><strong>Criando o modelo</strong> <code>User</code></p><pre><code class="language-shell">mkdir models
touch models/user.js</code></pre><p>No arquivo <code>models/user.js</code>, adicione o seguinte:</p><pre><code class="language-js">const mongoose = require('mongoose');
const Schema = mongoose.Schema;
-----
const userSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    }
})
module.exports = mongoose.model("User", userSchema, "users")</code></pre><p>No código acima, é criado um esquema para o usuário que contém os campos do usuário. Ao final do arquivo, o modelo ("User") é exportado com o esquema e a coleção ("users").</p><h3 id="conectando-o-banco-de-dados-do-mongodb-atlas">Conectando o banco de dados do MongoDB Atlas</h3><p>De acordo com <a href="https://www.mongodb.com/cloud/atlas">a documentação</a> (em inglês), "o MongoDB Atlas é o serviço global de banco de dados em nuvem para aplicações modernas".</p><p>Primeiro, precisamos nos registrar no <em>MongoDB Cloud</em>. Consulte <a href="https://docs.atlas.mongodb.com/getting-started/">esta documentação</a> (em inglês) para criar uma conta do Atlas e criar seu <em>cluster</em>.</p><p>Uma coisa que vale a pena observar é <strong>colocar o endereço IP de sua conexão na lista de permissões</strong>. Se você ignorar essa etapa, não terá acesso ao <em>cluster</em>, portanto preste atenção nessa parte.</p><p>O <em>cluster</em> é um pequeno servidor que gerenciará nossas coleções (semelhante às tabelas em bancos de dados do SQL). Para conectar seu <em>back-end</em> ao cluster, crie um arquivo <code>database.js</code>, que, como você pode ver, é necessário em <code>server.js</code>. Em seguida, digite o seguinte:</p><pre><code class="language-javascript">const mongoose = require('mongoose');
const connection = "mongodb+srv://username:&lt;password&gt;@&lt;cluster&gt;/&lt;database&gt;?retryWrites=true&amp;w=majority";
mongoose.connect(connection,{ useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false})
    .then(() =&gt; console.log("Database Connected Successfully"))
    .catch(err =&gt; console.log(err));</code></pre><p>Na variável de conexão, insira seu <code>nome de usuário</code> (para o <em>MongoDB Cloud</em>), sua <code>senha</code> (senha do cluster), seu <code>cluster</code> (endereço do seu cluster) e o <code>banco de dados</code> (nome do seu banco de dados). Tudo isso pode ser facilmente descoberto se você seguir a documentação.</p><h2 id="chamando-apis-no-front-end">Chamando APIs no <em>front-end</em></h2><p>Todas as APIs estarão disponíveis localmente em <code>localhost:5000</code>, assim como configuramos no <code>server.js</code>. Quando implantado no Heroku, o servidor usará a porta fornecida pelo servidor <code>(process.env.PORT)</code>.</p><p>Para facilitar as coisas, o React nos permite especificar um <em>proxy </em>para o qual as solicitações serão enviadas.</p><p>Abra o <code>package.json</code> e, logo antes da última chave, adicione o seguinte:</p><pre><code class="language-json">"proxy": "http://localhost:5000"</code></pre><p>Desse modo, podemos enviar solicitações diretamente para <code>api/users</code>. Quando nosso site for implantado e criado, a porta padrão da nossa aplicação será usada com a mesma API.</p><p>Abra <code>App.js</code> para o React e adicione o seguinte:</p><pre><code class="language-javascript">import React, {useState, useEffect} from 'react'
import axios from 'axios';
-----
const App = function () {
	const [users, setUsers] = useState(null);

	const [username, setUsername] = useState("");
	const [email, setEmail] = useState("");
	useEffect(() =&gt; {
		axios
			.get("/api/users")
			.then((users) =&gt; setUsers(users))
			.catch((err) =&gt; console.log(err));
	}, []);

	function submitForm() {
		if (username === "") {
			alert("Please fill the username field");
			return;
		}
		if (email === "") {
			alert("Please fill the email field");
			return;
		}
		axios
			.post("/api/users", {
				username: username,
				email: email,
			})
			.then(function () {
				alert("Account created successfully");
				window.location.reload();
			})
			.catch(function () {
				alert("Could not creat account. Please try again");
			});
	}
	return (
		&lt;&gt;
			&lt;h1&gt;My Project&lt;/h1&gt;
			{users === null ? (
				&lt;p&gt;Loading...&lt;/p&gt;
			) : users.length === 0 ? (
				&lt;p&gt;No user available&lt;/p&gt;
			) : (
				&lt;&gt;
					&lt;h2&gt;Available Users&lt;/h2&gt;
					&lt;ol&gt;
						{users.map((user, index) =&gt; (
							&lt;li key={index}&gt;
								Name: {user.name} - Email: {user.email}
							&lt;/li&gt;
						))}
					&lt;/ol&gt;
				&lt;/&gt;
			)}

			&lt;form onSubmit={submitForm}&gt;
				&lt;input
					onChange={(e) =&gt; setUsername(e.target.value)}
					type="text"
					placeholder="Enter your username"
				/&gt;
				&lt;input
					onChange={(e) =&gt; setEmail(e.target.value)}
					type="text"
					placeholder="Enter your email address"
				/&gt;
				&lt;input type="submit" /&gt;
			&lt;/form&gt;
		&lt;/&gt;
	);
};
export default App</code></pre><p>Os <em>hooks</em> <code>useState</code> e <code>useEffect</code> são usados ​​para manipular estados e efeitos colaterais <code>(sideEffects)</code>. O que basicamente está acontecendo é que o primeiro estado dos usuários é <code>null</code> e 'Loading...' (carregando) é mostrado no navegador.</p><p>No <code>useEffect[]</code>, <code>[]</code> é usado para especificar que, no estágio <code>componentDidMount</code> (quando o componente é montado), deve-se fazer uma solicitação do Axios para a API, que está sendo executada em <code>localhost:5000</code>. Se obtiver o resultado e não houver nenhum usuário, "<em>No user available</em>" (nenhum usuário disponível) será exibido. Caso contrário, será exibida uma lista numerada dos usuários.</p><p>Se você quiser saber mais sobre <code>useState</code> e <code>useEffect</code>, confira este artigo – <a href="https://blog.soshace.com/what-the-heck-is-react-hooks/">O que diabos são React Hooks?</a> (em inglês)</p><h2 id="implantando-no-heroku">Implantando no Heroku</h2><p>Para implantar sua aplicação no Heroku, você deve ter uma conta por lá.</p><p>Vá para <a href="https://www.heroku.com/">a página do Heroku</a> para criar uma conta. Em seguida, consulte <a href="https://devcenter.heroku.com/">a documentação</a> sobre como criar uma aplicação no Heroku. Verifique também <a href="https://devcenter.heroku.com/articles/heroku-cli">a documentação</a> do Heroku CLI. (links em inglês)</p><blockquote>Nota da tradução: reforçando, o Heroku não é mais gratuito. Caso seja sua intenção dar sequência a esse processo por lá, saiba que mesmo as alternativas iniciais agora são pagas.</blockquote><h3 id="criando-uma-aplica-o-no-heroku">Criando uma aplicação no Heroku</h3><p>Primeiro, faça login no Heroku:</p><pre><code class="language-shell">heroku login</code></pre><p>Isso vai redirecionar você para um URL no navegador onde você poderá fazer login. Quando terminar, você poderá continuar no terminal.</p><p>No mesmo diretório do projeto em React, execute o seguinte:</p><pre><code class="language-shell">heroku create</code></pre><p>Isso criará uma aplicação no Heroku e também fornecerá o URL para acessar o aplicativo.</p><h3 id="configurando-o-package-json">Configurando o package.json</h3><p>O Heroku usa seu arquivo <code>package.json</code> para saber quais scripts executar e quais dependências instalar para que seu projeto seja executado com sucesso.</p><p>No seu arquivo <code>package.json</code>, adicione o seguinte:</p><pre><code class="language-json">{
    ...
    "scripts": {
        ...
        "start": "node backend/server.js",
        "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install npm &amp;&amp; run build"
    },
    ...
    "engines": {
        "node": "10.16.0"
    }
}</code></pre><p>O Heroku executa uma pós-compilação que, como você poderá ver, instalará suas dependências e executará uma compilação do seu projeto em React. Em seguida, ele iniciará seu projeto com o script <code>start</code> que, basicamente, inicia seu servidor. Depois disso, seu projeto deverá funcionar bem.</p><p><code>engines</code> especifica as versões das <em>engines</em>, como <code>node</code> e <code>npm</code>, a serem instaladas.</p><h3 id="enviando-para-o-heroku">Enviando para o Heroku</h3><pre><code class="language-shell">git push heroku master</code></pre><p>O comando acima envia seu código para o Heroku. Lembre-se de incluir arquivos desnecessários em <code>.gitignore</code>.</p><p>Após alguns segundos, seu site estará pronto. Se houver algum erro, você pode verificar seu terminal ou acessar seu painel no navegador para visualizar os <em>logs</em> (registros) de criação (da <em>build</em>).</p><p>Agora, você pode visualizar seu site no URL que o Heroku enviou quando você executou <code>heroku create</code>.</p><p>Isso é tudo que há para fazer. Que bom que você chegou até aqui.</p><h2 id="resumo">Resumo</h2><p>É claro que há mais sobre aplicações da <em>stack</em> MERN.</p><p>Este artigo não se aprofundou em autenticações, login, sessões e tudo mais. Abordou apenas como implantar aplicações da <em>stack</em> MERN no Heroku e como trabalhar com MongoDB Atlas.</p><p>Você pode encontrar outros artigos como este no blog do autor: <a href="https://dillionmegida.com/">dillionmegida.com</a></p><p>Obrigado pela leitura.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Promises e Pokemons — como eu aprendi a pensar de modo assíncrono ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Kalalau Cantrell Se você vem aprendendo JavaScript, já deve ter ouvido falar de promises e de como elas são ótimas. Então, você deve ter pensado em pesquisar o básico a respeito. Talvez, você já tenha visto a documentação da MDN sobre promises [https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Using_promises]  ou artigos muito legais ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/promises-e-pokemons-como-eu-aprendi-a-pensar-de-modo-assincrono/</link>
                <guid isPermaLink="false">6676d50479dc5c03cfad506a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Mon, 01 Jul 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/06/1_J1GQbpmhZFXJ2AxGHLC1Og.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/promises-and-pokemon-how-i-learned-to-think-in-async-2ec098c2c90d/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Promises and Pokemon — how I learned to think in async</a>
      </p><p>Escrito por: Kalalau Cantrell</p><p>Se você vem aprendendo JavaScript, já deve ter ouvido falar de <em>promises</em> e de como elas são ótimas.</p><p>Então, você deve ter pensado em pesquisar o básico a respeito. Talvez, você já tenha visto a <a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Using_promises">documentação da MDN sobre <em>promises</em></a> ou artigos muito legais como <a href="https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261" rel="noopener">este</a>, escrito pelo Eric Elliott (em inglês), ou <a href="https://codeburst.io/javascript-learn-promises-f1eaa00c5461" rel="noopener">este</a>, escrito pelo Brandon Morelli (em inglês). Se você leu esses artigos ou outros mais, já deve ter visto o exemplo clássico de <em>promises</em> em ação.</p><pre><code>/* Exemplo clássico de promises */
 
let p = new Promise((resolve) =&gt; {
    setTimeout(function() {
        resolve('delícia');
    }, 1000);
});
 
p.then((mensagem1) =&gt; {
    console.log(mensagem1);      //imprime 'delícia' depois de 1s
    return new Promise((resolve) =&gt; {
        setTimeout(function() {
            resolve('de molho');
        }, 1000);
    });
}).then((mensagem2) =&gt; {
    console.log(mensagem2);      //imprime 'de molho' depois de mais 1s
});</code></pre><p>Depois de ver alguns desses exemplos, no entanto, você pode ter se perguntado se estava realmente entendendo <em>promises</em>. Nesse ponto, se você é como eu, entendeu conceitualmente o que as torna incríveis — elas permitem que você escreva código assíncrono em um padrão síncrono — mas deve estar se remoendo para ver um exemplo onde elas façam mais do que exibir uma série de linhas no <code>console.log</code> que disparem em tempos diferentes.</p><p>Então, o que foi que eu fiz? Criei um jogo simples de Pokemon, com uma batalha com base em turnos contra um <a href="https://bulbapedia.bulbagarden.net/wiki/Electabuzz_(Pok%C3%A9mon)" rel="noopener ugc nofollow">Electabuzz</a> (em inglês).</p><p><strong>Este artigo <strong>assume</strong> que você entendeu o exemplo de<strong> <em>promises</em> </strong>referido acima<strong>. </strong>Confira os recursos nos links do parágrafo introdutório<strong> </strong>se precisar refrescar sua memória<strong>.</strong></strong></p><h3 id="funcionalidade-b-sica">Funcionalidade básica</h3><p>O Electabuzz e o jogador começam com uma certa quantidade de pontos de vida (HP – do inglês, <em>hit points</em>). A primeira coisa a acontecer é um ataque do Electabuzz, onde o jogador perde um pouco de HP. Em seguida, o jogo <strong>aguarda<strong> </strong></strong>até que o jogador escolha um ataque e o utilize contra o Electabuzz.</p><p>Sim, o jogo simplesmente aguarda… e aguarda… essa é a parte onde eu comecei a de fato apreciar o valor do uso das <em>promises</em>. No momento em que o jogador opta por um ataque, o Electabuzz perde um pouco de HP e, em seguida, ataca novamente. Esse laço de repetição continua até que o HP do Electabuzz ou o HP do jogador chegue a zero.</p><h3 id="o-pseudoc-digo">O pseudocódigo</h3><pre><code>/* O Electabuzz e o jogador começam com uma certa quantidade de 
   pontos de vida (HP).
   A primeira coisa que acontece é um ataque do Electabuzz
   e o jogador perde um pouco de HP. */
 
function iniciarJogo() {
    //...define o HP da CPU e do jogador como 40
}
 
function vezDaCPU() {
    //...Electabuzz ataca! -5 HP para o jogador
}
 
/*
.
.
.
*/
 
iniciarJogo();
vezDaCPU();</code></pre><p>Até aqui, é bastante simples. É o momento de ajustarmos isso um pouco, de maneira que o Electabuzz ataque em um tempo mais natural. Eu queria fazer parecer que ele estava "pensando" sobre qual movimento fazer.</p><pre><code>//...
 
function vezDaCPU() {
    setTimeout(function() {
        //...Electabuzz ataca! -5 HP para o jogador
    }, 1000);       //o ataque acontece após 1 segundo
}
 
//...</code></pre><p>Enquanto isso, vamos colocar um pouco da magia das <em>promises</em> aqui para que possamos encadear funções que serão disparadas quando o Electabuzz termina seu ataque e somente depois disso, nem um milissegundo antes. Afinal, esse é um jogo com base em turnos.</p><pre><code>//...
 
function vezDaCPU() {
    return new Promise((resolve) =&gt; {
        setTimeout(function() {
            //...Electabuzz ataca! -5 HP para o jogador
            resolve();
        }, 1000);       //o ataque acontece após 1 segundo,
    });                 //que é o tempo que a promise leva para resolver
}
 
//...</code></pre><p>Ótimo! A configuração acima nos permitirá, mais tarde, fazer o seguinte:</p><pre><code>//...
 
vezDaCPU()
    .then(() =&gt; vezDoJogador());</code></pre><p>Agora, passemos para o código do jogador.</p><pre><code>/*O jogo aguarda até que o jogador selecione um ataque
  para usar no Electabuzz. Quando ele escolhe o ataque, 
  o Electabuzz perde um pouco de HP e ataca novamente.*/

//...
 
function vezDoJogador() {
 
    //....????....????
 
}
 
//...</code></pre><p>Como escreveremos uma função que, ao ser chamada, aguardará pela entrada do usuário antes de terminar sua execução? Sabemos que isso precisa envolver de alguma maneira um <strong><strong><em>event listener</em></strong></strong> (em português, algo como "escutador" ou observador de eventos) para a parte da entrada do usuário. Também sabemos que deve poder usar <strong><strong><em>promises</em></strong></strong> de algum jeito para a parte assíncrona… como faremos, porém, para juntar as duas coisas?</p><p>O que descobri foi que você poder 1) criar uma <em>promise</em>, 2) dentro da <em>promise</em>, adicionar um <em>event listener</em> para, em nosso caso, um evento de clique de um botão e 3) se a função for chamada pelo <em>event listener</em>, a <em>promise</em> ser resolvida, o que fará com que você consiga o efeito de aguardar.</p><pre><code>//...
 
function vezDoJogador() {
    return new Promise((resolve) =&gt; {                       // (1)
        botaoDoJogador.addEventListener('click', function() {    // (2)
            //...O jogador ataca! -5 HP para o Electabuzz
            resolve();                                      // (3)
        });
    });
}
 
//...</code></pre><p>Aí está! Agora, conseguimos fazer isto:</p><pre><code>//...
 
vezDaCPU()
    .then(() =&gt; vezDoJogador())
    .then(() =&gt; vezDaCPU())
    .then(() =&gt; vezDoJogador());</code></pre><p>Observe que cada chamada de <code>vezDoJogador()</code> no código acima simplesmente aguardará… e aguardará um pouco mais… até que o jogador selecione seu ataque. Somente se a execução continuar o turno do Electabuzz chegará.</p><p>No entanto, por que devemos escrever assim quando o mesmo código pode ser obtido na forma equivalente em <em>async/await</em>, que parece muito mais limpa? Se você seguiu o que fiz com <em>promises</em> até aqui, não há uma grande diferença para aquilo que <em>async/await</em> faz. Compare o código abaixo com o código acima e verá que são equivalentes, mas o código abaixo parece mais bem organizado.</p><pre><code>//...
 
async function sequenciaDeJogo() {
    await vezDaCPU();
    await vezDoJogador();
    await vezDaCPU();
    await vezDoJogador();
}
 
sequenciaDeJogo();</code></pre><p>Se quiser saber mais sobre <em>async/await</em>, confira <a href="https://www.freecodecamp.org/news/oh-yes-async-await-f54e5a079fc1">este artigo</a> (em inglês) de Tiago Lopes Ferreira ou <a href="https://wesbos.github.io/Async-Await-Talk/#1" rel="noopener ugc nofollow">estes slides</a> (em inglês) de Wes Bos.</p><p>Bem, nosso código agora consegue executar algumas rodadas de combate com base em turnos com o Electabuzz. Porém, ainda precisamos de um modo de fazer o jogo terminar.</p><pre><code>//...
 
async function sequenciaDeJogo() {
    await vezDaCPU();
    if (/*HP do jogador é 0*/) {
        //...fim de jogo
    }
    await vezDoJogador();
    if (/*HP do Electabuzz é 0*/) {
        //...fim de jogo
    }
    await vezDaCPU();
    if (/*HP do jogador é 0*/) {
        //...fim de jogo
    }
    await vezDoJogador();
    if (/*HP do Electabuzz é 0*/) {
        //...fim de jogo
    }
 
    // poderíamos repetir essa lógica manualmente tanto quanto 
    // precisássemos..., mas não há um jeito mais inteligente?
}
 
sequenciaDeJogo();</code></pre><p>Por fim, queremos que o programa continue a ser executado por conta própria até que as condições de fim de jogo sejam atendidas. Em vez de repetir manualmente as lógicas de <code>cpuTurn()</code> e <code>playerTurn()</code> como viemos fazendo, podemos fazer isso recursivamente, chamando a função <code>gameLoop()</code> até que uma das condições seja atendida.</p><pre><code>//...
 
async function sequenciaDeJogo() {
    await vezDaCPU();
    if (/*HP do jogador é 0*/) {
        //...fim de jogo
    }
    await vezDoJogador();
    if (/*HP do Electabuzz é 0*/) {
        //...fim de jogo
    } else {
        sequenciaDeJogo();     //sequenciaDeJogo chama a si mesmo até que
    }                          //atenda as condições de fim de jogo
}
 
sequenciaDeJogo();</code></pre><p>A função <code>sequenciaDeJogo</code> será executada e continuará a chamar a si mesma e a executar até que o HP do Electabuzz ou o HP do jogador chegue a zero. Se quiser saber mais sobre recursão, assista <a href="https://youtu.be/k7-N8R0-KY4" rel="noopener ugc nofollow">este vídeo no YouTube</a> (em inglês), de MPJ. Enquanto estiver por lá, confira outros vídeos do canal dele, o <em>Fun Fun Function</em>. Ele explica muito bem tópicos complexos de um modo divertido.</p><p>Vamos agora olhar o pseudocódigo completo:</p><pre><code>function iniciarJogo() {
    //...define o HP da CPU e do jogador como 40
}
 
function vezDaCPU() {
    return new Promise((resolve) =&gt; {
        setTimeout(function() {
            //...O Electabuzz ataca! -5 HP para o jogador
            resolve();
        }, 1000);       //o ataque acontece após 1 segundo,
    });                 //que é o tempo para a promise resolver
}
 
function vezDoJogador() {
    return new Promise((resolve) =&gt; {
        botaoDoJogador.addEventListener('click', function() {
            //...O jogador ataca! -5 HP para o Electabuzz
            resolve();      //essa promise não resolve até que
        });                 //a entrada do usuário desejada é recebida
    });
}
 
async function sequenciaDeJogo() {
    await vezDaCPU();
    if (/*HP do jogador é 0*/) {
        //...fim de jogo
    }
    await vezDoJogador();
    if (/*HP do Electabuzz é 0*/) {
        //...fim de jogo
    } else {
        sequenciaDeJogo();     //sequenciaDeJogo chama a si mesmo até que
    }                          //atenda as condições de fim de jogo
}
 
iniciarJogo();
sequenciaDeJogo();</code></pre><h3 id="o-c-digo">O código</h3><p>Agora que terminamos o pseudocódigo, veja neste Pen como eu implementei a lógica com JavaScript de verdade:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_jaJZad" src="https://codepen.io/klcantrell/embed/preview/jaJZad?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=jaJZad" title="Electabuzz Game Loop" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h3 id="conclus-o">Conclusão</h3><p>Obrigado pela leitura. Esse pequeno experimento com <em>promises</em> me fez ver que as <em>promises </em>simplificam muito no que se trata de compor código assíncrono. Embora o exemplo típico de <em>promises </em>com <em>console.logs</em> e <em>setTimeouts</em> ilustrasse bem o conceito, eu não me empolguei muito com ele, por isso decidi criar esse jogo simples para me empolgar com as <em>promises</em> de vez. Espero que você tenha captado um pouco dessa empolgação e ficado empolgado com elas como eu. Se houver algum especialista em código assíncrono lendo este artigo, seria ótimo saber sua opinião quanto a maneiras melhores de se obter a mesma funcionalidade (como <em>generators</em>, por exemplo). Se algo não ficou claro no artigo, mande mensagem e eu tentarei esclarecer.</p><p><strong>Fique à vontade para entrar em contato pelo<strong> </strong></strong><a href="https://www.twitter.com/kalalaucantrell" rel="noopener ugc nofollow"><strong><strong>Twitter</strong></strong></a><strong><strong>.</strong></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar um pacote do npm lindo e pequeno – e como publicá-lo ]]>
                </title>
                <description>
                    <![CDATA[ Você não vai acreditar; é muito fácil! Se você já criou muitos módulos do npm, pode pular essa seção. Se não, vamos fazer uma rápida introdução. Versão abreviada Um módulo do npm necessita apenas de um arquivo package.json com as propriedades  name e version. Olá! Aí está você, apenas ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-um-pacote-do-npm-lindo-e-pequeno-e-como-publica-lo/</link>
                <guid isPermaLink="false">65fb55b64f187703fea1fff2</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Esdras Ferreira da Silva ]]>
                </dc:creator>
                <pubDate>Mon, 10 Jun 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/0_7m8mTkj_Fp916sdm.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-make-a-beautiful-tiny-npm-package-and-publish-it-2881d4307f78/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to make a beautiful, tiny npm package and publish it</a>
      </p><p>Você não vai acreditar; é muito fácil!</p><p>Se você já criou muitos módulos do npm, pode pular essa seção. Se não, vamos fazer uma rápida introdução.</p><h4 id="vers-o-abreviada">Versão abreviada</h4><p>Um módulo do npm necessita <strong>apenas </strong>de um arquivo <code>package.json</code> com as propriedades <strong>name </strong>e <strong>version</strong>.</p><h3 id="ol-">Olá!</h3><p>Aí está você, apenas um pequeno elefante com a vida toda pela frente. Você não é um mestre em fazer pacotes do npm, mas adoraria saber como, certo? Todos os grandes elefantes andam por aí com suas patas gigantes, fazendo pacotes após pacotes. Você pode pensar:</p><blockquote><em>"Não consigo competir com isso".</em></blockquote><p>Bem, estou aqui para dizer para você que você consegue! Não precisa duvidar da sua capacidade.</p><p>Vamos começar!</p><h3 id="voc-n-o-um-elefante">Você não é um elefante</h3><p>Entenda o que eu disse como uma <a href="https://brasilescola.uol.com.br/gramatica/metafora.htm">metáfora</a>.</p><p>Você já se perguntou como elefantes bebês são chamados?</p><p><em>Com certeza, já. </em>Um elefante bebê é um "bebê elefante", oras.</p><h3 id="eu-acredito-em-voc-">Eu acredito em você</h3><p>A <a href="https://en.wikipedia.org/wiki/Impostor_syndrome"></a><a href="https://pt.wikipedia.org/wiki/S%C3%ADndrome_do_impostor">autossabotagem</a> é real. Acaba ocorrendo que as pessoas deixam de fazer coisas muito legais. Você acha que você não será bem-sucedido. Então, você acaba não fazendo nada, mas exalta as pessoas que fazem coisas incríveis. Isso é muito irônico. Por isso, vou mostrar para você o menor módulo npm possível.</p><p>Em breve, você terá várias ideias de módulos npm ao seu alcance, código reutilizável até onde os olhos podem ver – tudo isso sem truques e sem instruções complexas.</p><h3 id="as-instru-es-complexas">As instruções complexas</h3><p>Eu prometi que eu não usaria instruções complexas, mas usei. Elas, porém, não são tão complexas assim. Você vai me perdoar um dia.</p><h4 id="passo-1-conta-do-npm"><strong>Passo 1: conta do npm</strong></h4><p>Você vai precisar de uma. É parte do acordo. <a href="https://www.npmjs.com/signup" rel="noopener">Crie a conta aqui</a>.</p><h4 id="passo-2-login">Passo 2: login</h4><p>Você fez a conta do npm? Já fez? Legal. Também vou assumir que você sabe usar <a href="https://www.davidbaumgold.com/tutorials/command-line/">linha de comando</a>/<a href="https://www.davidbaumgold.com/tutorials/command-line/">console</a> etc (textos em inglês). Eu vou chamar de terminal a partir de agora. Aparentemente, há uma diferença.</p><p>Vá no terminal e escreva:</p><pre><code class="language-bash">npm adduser</code></pre><p>Você também pode usar o comando:</p><pre><code class="language-bash">npm login</code></pre><p>Escolha o comando que agrade a você.</p><p>Você receberá uma mensagem pedindo seu <strong>nome de usuário</strong>, <strong>senha </strong>e <strong>e-mail</strong>.</p><p>A mensagem será parecida com esta:</p><pre><code>Logged in as bamblehorse to scope @username on https://registry.npmjs.org/.</code></pre><p>Vamos em frente!</p><h3 id="hora-de-fazer-um-pacote">Hora de fazer um pacote</h3><p>Primeiramente, precisamos de uma pasta para colocar nosso código. Crie uma pasta da maneira que se sentir confortável. Eu vou chamar o meu pacote de <strong>tiny </strong>(palavra em inglês para <em>minúsculo</em>) porque o pacote será, de fato, muito pequeno. Eu adicionei alguns comandos de terminal para aqueles que não estão familiarizados com eles.</p><pre><code class="language-bash">md tiny</code></pre><p>Nessa pasta, vamos precisar de um arquivo <a href="https://docs.npmjs.com/files/package.json" rel="noopener"><strong>package.json</strong></a><strong>. </strong>Se você já usa <a href="https://en.wikipedia.org/wiki/Node.js" rel="noopener">Node.js</a>, já viu esse arquivo antes. É um arquivo <a href="https://en.wikipedia.org/wiki/JSON" rel="noopener">JSON</a> que inclui informações sobre o seu projeto e possui uma infinidade de opções diferentes. Neste tutorial, vamos focar apenas em duas delas.</p><pre><code class="language-bash">cd tiny &amp;&amp; touch package.json</code></pre><h4 id="qual-deve-ser-o-tamanho-do-pacote">Qual deve ser o tamanho do pacote?</h4><p>Muito pequeno.</p><p>Todos os tutoriais sobre fazer um pacote npm, inclusive o da documentação oficial, dizem para você adicionar determinados campos no seu <code>package.json</code>. Vamos tentar publicar nosso pacote com o mínimo possível até ele funcionar. Como se fosse um <a href="https://pt.wikipedia.org/wiki/Test-driven_development">TDD</a> para um pacote do npm mínimo.</p><p><strong>Observação: </strong>eu estou mostrando isso para demonstrar que fazer um pacote do npm não precisa ser complicado. Para ser útil para a comunidade em geral, um pacote precisa de algumas coisas a mais – e vamos abordar isso mais adiante no artigo.</p><h4 id="publica-o-primeira-tentativa">Publicação: primeira tentativa</h4><p>Para publicar o seu pacote do npm, você deve executar um comando bem conveniente: <strong>npm publish</strong>.</p><p>Então, temos um <code>package.json</code> vazio na nossa pasta e vamos fazer uma tentativa:</p><pre><code class="language-bash">npm publish</code></pre><p>Opa!</p><p>Recebemos um erro:</p><pre><code>npm ERR! file package.json
npm ERR! code EJSONPARSE
npm ERR! Failed to parse json
npm ERR! Unexpected end of JSON input while parsing near ''
npm ERR! File: package.json
npm ERR! Failed to parse package.json data.
npm ERR! package.json must be actual JSON, not just JavaScript.
npm ERR!
npm ERR! Tell the package author to fix their package.json file. JSON.parse</code></pre><p>O npm não gostou muito do seu pacote.</p><p>Faz sentido.</p><h4 id="publica-o-segunda-tentativa">Publicação: segunda tentativa</h4><p>Vamos dar um nome para o nosso pacote no arquivo <code>package.json</code>:</p><pre><code class="language-json">{
"name": "@bamblehorse/tiny"
}</code></pre><p>Você deve ter percebido que eu adicionei meu username do npm no começo.</p><p>Por que fazer isso?</p><p>Usando o nome <strong>@bamblehorse/tiny </strong>ao invés de apenas <strong>tiny, </strong>criamos um pacote sob o escopo do nosso <em>username</em>. Isso é chamado de <a href="https://docs.npmjs.com/misc/scope" rel="noopener"><strong>scoped package</strong></a><strong> </strong>(em português, pacote com escopo).<strong> </strong>Isso nos permite usar nomes curtos que talvez já foram usados. Por exemplo, o pacote <a href="https://www.npmjs.com/package/tiny" rel="noopener"><strong>tiny</strong></a><strong> </strong>já existe no npm.</p><p>Você já deve ter visto isso em bibliotecas populares como a do <em>framework</em> <a href="https://angular.io/" rel="noopener">Angular</a>, da Google. Eles possuem alguns <em>scoped packages, </em>como <a href="https://www.npmjs.com/package/@angular/core" rel="noopener">@angular/core</a> e <a href="https://www.npmjs.com/package/@angular/http" rel="noopener">@angular/http</a>.</p><p>Bem legal, não?</p><p>Vamos tentar publicar uma segunda vez:</p><pre><code class="language-bash">npm publish</code></pre><p>O erro é menor dessa vez – tivemos um progresso.</p><pre><code>npm ERR! package.json requires a valid "version" field</code></pre><p>Cada pacote do npm precisa de uma versão para que os desenvolvedores saibam se eles podem atualizar com segurança para uma nova versão do nosso pacote sem quebrar o resto do código deles. O sistema de versionamento do npm é chamado de <a href="https://semver.org/" rel="noopener"><strong>SemVer</strong></a><strong>, </strong>que significa <strong>Semantic Versioning </strong>(em português, versionamento semântico).</p><p>Não se preocupe muito em entender os nomes mais complexos de versão, mas aqui está um resumo de como os mais básicos funcionam:</p><blockquote>Dado um número de versão MAJOR.MINOR.PATCH, incremente o:</blockquote><blockquote>1. MAJOR quando você faz mudanças incompatíveis na API.</blockquote><blockquote>2. MINOR quando você adiciona uma funcionalidade de modo compatível com a versão anterior, e</blockquote><blockquote>3. PATCH quando você conserta erros de maneira compatível com a última versão.</blockquote><blockquote>Rótulos adicionais para pré-lançamento e metadados de build estão disponíveis como extensões do formato MAJOR.MINOR.PATCH.</blockquote><blockquote><a href="https://semver.org/" rel="noopener">https://semver.org</a></blockquote><h4 id="publicando-terceira-tentativa"><strong>Publicando: terceira tentativa</strong></h4><p>Vamos colocar no nosso <code>package.json</code> a versão: <strong>1.0.0</strong> – o primeiro lançamento major.</p><pre><code class="language-json">{
"name": "@bamblehorse/tiny",
"version": "1.0.0"
}</code></pre><p>Vamos publicar!</p><pre><code class="language-bash">npm publish</code></pre><p>Ah, droga.</p><pre><code>npm ERR! publish Failed PUT 402
npm ERR! code E402
npm ERR! You must sign up for private packages : @bamblehorse/tiny</code></pre><p>Permita-me explicar.</p><p><em>Scoped packages </em>são automaticamente publicados de maneira privada, pois, além de serem úteis para usuários únicos como nós, eles também são utilizados por empresas para compartilhar código entre projetos. Se tivéssemos publicado um pacote normal, nossa jornada teria acabado aqui.</p><p>Tudo que precisamos mudar é dizer para o npm que, na verdade, queremos que todo mundo possa usar esse módulo – não o manter trancado nos cofres deles. Portanto, executamos o seguinte comando:</p><pre><code class="language-bash">npm publish --access=public</code></pre><p>De repente, o sucesso!</p><pre><code>+ @bamblehorse/tiny@1.0.0</code></pre><p>Recebemos um sinal de adição, o nome do nosso pacote e a versão.</p><p>Conseguimos — estamos no clube do npm.</p><p>Estou animado. <em>Você deve estar animado também.</em></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_oBaHFxAXy-BWtzyAKeMGBQ.png" class="kg-image" alt="1_oBaHFxAXy-BWtzyAKeMGBQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_oBaHFxAXy-BWtzyAKeMGBQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_oBaHFxAXy-BWtzyAKeMGBQ.png 695w" width="695" height="346" loading="lazy"><figcaption>Removi algumas informações deixando uma fita azul bonita por cima</figcaption></figure><h4 id="voc-viu">Você viu?</h4><blockquote>npm loves you <em>(em português, o npm ama você)</em></blockquote><p>Que fofo!</p><p>A <a href="https://www.npmjs.com/package/@bamblehorse/tiny/v/1.0.0" rel="noopener">primeira versão</a> está disponível no npm!</p><h3 id="seguindo-em-frente">Seguindo em frente</h3><p>Se quisermos ser levados a sério como desenvolvedores e se quisermos que nosso pacote seja usado, precisaremos mostrar o código para as pessoas e dizer para elas como elas devem usar. Em geral, fazemos isso colocando nosso código em algum lugar público e adicionando um arquivo <code>readme</code>.</p><p>Também precisamos de algum código. É verdade, não temos código ainda.</p><p>O Github é um ótimo lugar para colocar o seu código. Vamos fazer um <a href="https://github.com/new">novo repositório</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_NGHjzcMgnzBtmSFfQuqVow.png" class="kg-image" alt="1_NGHjzcMgnzBtmSFfQuqVow" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_NGHjzcMgnzBtmSFfQuqVow.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_NGHjzcMgnzBtmSFfQuqVow.png 723w" sizes="(min-width: 720px) 720px" width="723" height="614" loading="lazy"><figcaption>Criando um repositório no GitHub</figcaption></figure><h4 id="readme-">README!</h4><p>Eu me acostumei a escrever arquivos <strong>README </strong>(do inglês "<em>read me"</em> – em português, leia-me) ao invés de <strong>readme</strong>. Você não tem que fazer isso mais. É uma convenção divertida. Vamos adicionar algumas <em>badges </em>descoladas do <a href="https://shields.io/" rel="noopener">shields.io</a> para as pessoas saberem que somos superlegais e profissionais. Aqui está uma que permite as pessoas saberem a versão atual do nosso pacote:‌</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_ZbzgGAfTeBlqNH2gtLy-GQ.png" class="kg-image" alt="1_ZbzgGAfTeBlqNH2gtLy-GQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_ZbzgGAfTeBlqNH2gtLy-GQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_ZbzgGAfTeBlqNH2gtLy-GQ.png 700w" width="700" height="247" loading="lazy"><figcaption>npm (com escopo)</figcaption></figure><p>A próxima <em>badge </em>é interessante. Ela falhou porque não temos nenhum código, na verdade. Deveríamos, realmente, escrever um pouco de código...</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_mxZkgckYLK16mhkRte1Bqw.png" class="kg-image" alt="1_mxZkgckYLK16mhkRte1Bqw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_mxZkgckYLK16mhkRte1Bqw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_mxZkgckYLK16mhkRte1Bqw.png 699w" width="699" height="244" loading="lazy"><figcaption>npm com tamanho reduzido (minificado)</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_gY_-15Q4rLU129dXLg5ibQ.png" class="kg-image" alt="1_gY_-15Q4rLU129dXLg5ibQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_gY_-15Q4rLU129dXLg5ibQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_gY_-15Q4rLU129dXLg5ibQ.png 800w" sizes="(min-width: 720px) 720px" width="800" height="212" loading="lazy"><figcaption>Nosso pequeno readme</figcaption></figure><h4 id="licen-a-para-programar">Licença para <em>programar</em></h4><p>O título é definitivamente uma <a href="https://www.imdb.com/title/tt0097742/">referência a James Bond</a>. Na verdade, eu me esqueci de adicionar uma licença. Uma licença permite que as pessoas saibam em quais situações elas podem usar seu código. Há várias <a href="https://choosealicense.com/">licenças diferentes</a>.</p><p>Existe uma página legal chamada <em>insights</em> em todo repositório do GitHub onde você pode checar várias estatísticas – incluindo os padrões da comunidade para o projeto. Vou adicionar minha licença por lá.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_hkUyteXGLLTDt0WwKEpZ6A.png" class="kg-image" alt="1_hkUyteXGLLTDt0WwKEpZ6A" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_hkUyteXGLLTDt0WwKEpZ6A.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_hkUyteXGLLTDt0WwKEpZ6A.png 800w" sizes="(min-width: 720px) 720px" width="800" height="552" loading="lazy"><figcaption>Recomendações da comunidade</figcaption></figure><p>Então, você vai para esta página:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_ZWgFtTjkB8RpBDfRsCsLUQ.png" class="kg-image" alt="1_ZWgFtTjkB8RpBDfRsCsLUQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/1_ZWgFtTjkB8RpBDfRsCsLUQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/1_ZWgFtTjkB8RpBDfRsCsLUQ.png 800w" sizes="(min-width: 720px) 720px" width="800" height="379" loading="lazy"><figcaption>O Github oferece a você um resumo bem útil de cada licença</figcaption></figure><h4 id="o-c-digo">O código</h4><p>Ainda não temos um código. Isso é um pouco constrangedor.</p><p>Vamos adicionar o código agora antes que percamos toda a credibilidade.</p><figure class="kg-card kg-code-card"><pre><code class="language-js">module.exports = function tiny(string) {
  if (typeof string !== "string") throw new TypeError("Tiny wants a string!");
  return string.replace(/\s/g, "");
};</code></pre><figcaption>Inútil, eu sei — mas lindo</figcaption></figure><p>Aí está. Uma função minúscula (do inglês, <strong><em>tiny</em></strong>)<strong> </strong>que remove todos os espaços de uma string.</p><p>Então, tudo que um pacote do npm exige é um arquivo <strong>index.js</strong>. Esse é o ponto de entrada do seu pacote. Você pode fazer isso de diferentes maneiras à medida que o seu pacote fica mais complexo. Por agora, porém, isso é tudo de que precisamos.</p><h3 id="j-chegamos-l-"><strong>Já chegamos lá?</strong></h3><p>Estamos bem perto. Provavelmente, deveríamos atualizar nosso <strong>package.json</strong> minimalista e adicionar algumas instruções ao nosso <strong>readme.md</strong>. Senão, ninguém saberia como usar nosso belíssimo código.</p><h4 id="package-json">package.json</h4><figure class="kg-card kg-code-card"><pre><code class="language-json">{
  "name": "@bamblehorse/tiny",
  "version": "1.0.0",
  "description": "Removes all spaces from a string",
  "license": "MIT",
  "repository": "bamblehorse/tiny",
  "main": "index.js",
  "keywords": [
    "tiny",
    "npm",
    "package",
    "bamblehorse"
  ]
}</code></pre><figcaption>Descritivo!</figcaption></figure><p>Adicionamos:</p><ul><li><a href="https://docs.npmjs.com/files/package.json#description-1" rel="noopener">description</a>: uma descrição curta do pacote</li><li><a href="https://docs.npmjs.com/files/package.json#repository" rel="noopener">repository</a>: compatível com o GitHub — então, você pode escrever <strong>username/repo</strong></li><li><a href="https://docs.npmjs.com/files/package.json#license" rel="noopener">license</a>: a licença da MIT, neste caso</li><li><a href="https://docs.npmjs.com/files/package.json#main" rel="noopener">main</a>: o ponto de entrada do pacote, relativo à pasta raiz</li><li><a href="https://docs.npmjs.com/files/package.json#keywords" rel="noopener">keywords</a>: uma lista de palavras-chave usadas para descobrir seu pacote em uma pesquisa no npm.</li></ul><h4 id="readme-md">readme.md</h4><!--kg-card-begin: markdown--><h1 id="bamblehorsetiny">@bamblehorse/tiny</h1>
<p><a href="https://www.npmjs.com/package/@bamblehorse/tiny"><img src="https://img.shields.io/npm/v/@bamblehorse/tiny.svg" alt="npm (scoped)" width="600" height="400" loading="lazy"></a><br>
<a href="https://www.npmjs.com/package/@bamblehorse/tiny"><img src="https://img.shields.io/bundlephobia/min/@bamblehorse/tiny.svg" alt="npm bundle size (minified)" width="600" height="400" loading="lazy"></a></p>
<p>Removes all spaces from a string.</p>
<h2 id="install">Install</h2>
<pre><code>$ npm install @bamblehorse/tiny
</code></pre>
<h2 id="usage">Usage</h2>
<pre><code class="language-js">const tiny = require("@bamblehorse/tiny");

tiny("So much space!");
//=&gt; "Somuchspace!"

tiny(1337);
//=&gt; Uncaught TypeError: Tiny wants a string!
//    at tiny (&lt;anonymous&gt;:2:41)
//    at &lt;anonymous&gt;:1:1
</code></pre>
<!--kg-card-end: markdown--><p>Adicionamos instruções sobre como instalar e usar o pacote. Legal!</p><p>Se você quer um bom modelo para seu <em>readme</em>, é só conferir pacotes populares na comunidade de código aberto (do inglês, <em>open source</em>) e usar os formatos deles para começar.</p><h3 id="conclus-o">Conclusão</h3><p>Vamos publicar nosso pacote espetacular.</p><h4 id="vers-o">Versão</h4><p>Primeiramente, vamos atualizar a versão com o comando <a href="https://docs.npmjs.com/cli/version" rel="noopener">npm version</a>.</p><p>Esse é um lançamento <em>major</em>. Então, escrevemos:</p><pre><code class="language-bash">npm version major</code></pre><p>O que nos retorna:</p><pre><code>v2.0.0</code></pre><h4 id="publique-">Publique!</h4><p>Vamos rodar nosso novo comando favorito:</p><pre><code class="language-bash">npm publish</code></pre><p>Está pronto:</p><pre><code>+ @bamblehorse/tiny@2.0.0</code></pre><h3 id="coisas-legais">Coisas legais</h3><p>A <a href="https://packagephobia.now.sh/result?p=%40bamblehorse%2Ftiny" rel="noopener">Package Phobia</a> dá um ótimo resumo do seu pacote do npm. Você também pode verificar cada arquivo em sites como o <a href="https://unpkg.com/@bamblehorse/tiny@2.0.0/" rel="noopener">Unpkg</a>.</p><h3 id="agradecimento">Agradecimento</h3><p>Foi uma jornada maravilhosa que acabamos de fazer juntos. Espero que você tenha aproveitado tanto quanto eu. Se puder, deixe uma estrela para o pacote que nós acabamos de criar aqui:</p><h4 id="-github-com-bamblehorse-tiny-"><strong>★ <a href="https://github.com/Bamblehorse/tiny" rel="noopener">Github.com/Bamblehorse/tiny</a> ★</strong></h4><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/0_qmkE3zw9beF6fP_0.png" class="kg-image" alt="0_qmkE3zw9beF6fP_0" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/0_qmkE3zw9beF6fP_0.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/0_qmkE3zw9beF6fP_0.png 800w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>"Um elefante parcialmente submerso na água" – autor: <a href="https://unsplash.com/@jakobowens1?utm_source=medium&amp;utm_medium=referral">Jakob Owens</a>, fonte: <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Siga o autor no <a href="https://medium.com/@Bamblehorse" rel="noopener">Medium</a> ou no próprio <a href="https://github.com/Bamblehorse" rel="noopener">GitHub</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 10 bibliotecas do JavaScript que valem a pena experimentar ]]>
                </title>
                <description>
                    <![CDATA[ > Tradução em português europeu O JavaScript é uma das linguagens mais populares da web. Ainda que tenha sido inicialmente desenvolvida apenas para páginas da web, tem apresentado um crescimento exponencial nas duas últimas décadas. Atualmente, o JavaScript é capaz de fazer quase tudo. Ele funciona com diferentes plataformas e ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/10-bibliotecas-do-javascript-que-valem-a-pena-experimentar/</link>
                <guid isPermaLink="false">66212774e096720470bd1a5c</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isa Ribeiro ]]>
                </dc:creator>
                <pubDate>Sun, 09 Jun 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/5f9c9999740569d1a4ca20a6.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/10-javascript-libraries-you-should-try/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">10 Awesome JavaScript Libraries You Should Try Out</a>
      </p><blockquote>Tradução em português europeu</blockquote><p>O JavaScript é uma das linguagens mais populares da web. Ainda que tenha sido inicialmente desenvolvida apenas para páginas da web, tem apresentado um crescimento exponencial nas duas últimas décadas.</p><p>Atualmente, o JavaScript é capaz de fazer quase tudo. Ele funciona com diferentes plataformas e dispositivos, incluindo o que é denominado como a Internet das Coisas. Com o recente lançamento do SpaceX Dragon, o JavaScript já chegou, inclusive, ao espaço.</p><p>Uma das razões para a popularidade do JavaScript é a disponibilidade de um grande número de <em>frameworks </em>e bibliotecas. Isso torna a programação mais fácil comparada à programação com JavaScript mais tradicional.</p><p>Existem bibliotecas para quase tudo. Todos os dias, são desenvolvidas muitas mais. Com tantas bibliotecas à escolha, porém, torna-se difícil estarmos atualizados relativamente a cada uma delas e a como elas podem estar ajustadas especificamente às nossas necessidades.</p><p>Neste artigo, vamos discutir as 10 bibliotecas de JS mais populares, e que poderás usar num próximo projecto.</p><h1 id="leaflet"><strong><a href="https://leafletjs.com/">Leaflet</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-17.png" class="kg-image" alt="image-17" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/image-17.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-17.png 760w" sizes="(min-width: 720px) 720px" width="760" height="326" loading="lazy"><figcaption>Leaflet</figcaption></figure><p>A Leaflet é a melhor biblioteca <em>open source</em> para adicionar mapas interativos para telemóveis na tua aplicação.</p><p>O seu tamanho reduzido (39kB) torna-a uma boa alternativa a considerar, quando comparada com outras bibliotecas de mapas. Com eficiência quando utilizada em diferentes plataformas e uma API bem documentada, ela tem tudo o que é preciso para se apaixonar.</p><p>Aqui está uma amostra de código para criar um mapa com a Leaflet:</p><pre><code>var map = new L.Map("map", {
    center: new L.LatLng(40.7401, -73.9891),
    zoom: 12,
    layers: new L.TileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png")
});</code></pre><p>Na Leaflet, temos de providenciar uma camada de mosaicos visto que não existe uma por definição. Isso também significa, contudo, que podemos escolher de uma ampla variedade de camadas (gratuitas e <em>premium</em>). Podes explorar as diferentes camadas de mosaicos <a href="https://leaflet-extras.github.io/leaflet-providers/preview/">aqui</a>.</p><p>Se tiveres mais interesse, <a href="https://leaflet-extras.github.io/leaflet-providers/preview/">lê mais sobre a Leaflet</a> e segue os <a href="https://leafletjs.com/examples.html">tutoriais</a> (página em inglês).</p><h1 id="fullpage-js"><strong><a href="https://alvarotrigo.com/fullPage/">fullPage.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ezgif.com-video-to-gif-1--1.gif" class="kg-image" alt="ezgif.com-video-to-gif-1--1" width="600" height="278" loading="lazy"><figcaption>fullPage</figcaption></figure><p>Esta biblioteca <em>open source</em> ajuda-nos a criar sites com capacidade de rolagem em tela completa, como podes ver no GIF acima. É fácil de usar e tem várias opções de personalização. Por isso, não é uma grande surpresa que seja usada por milhares de programadores e que tenha 30 mil estrelas no GitHub.</p><p>Em baixo, tens uma demonstração no Codepen para poderes experimentar:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_WNrLvLG" src="https://codepen.io/lelouchb/embed/preview/WNrLvLG?default-tabs=html%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=WNrLvLG" title="fullPage.js - Base example" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Podes usá-la com <em>frameworks</em> conhecidas como:</p><ul><li><a href="https://alvarotrigo.com/react-fullpage/">react-fullpage</a></li><li><a href="https://alvarotrigo.com/vue-fullpage/">vue-fullpage</a></li><li><a href="https://alvarotrigo.com/angular-fullpage/">angular-fullpage</a></li></ul><p>Encontrei a biblioteca há cerca de um ano atrás e, desde então, tem sido uma das minhas bibliotecas preferidas. É das poucas bibliotecas que uso em quase todos os meus projectos. Se ainda não começaste a usá-la, então experimenta-a. Não vais ficar desapontado.</p><h1 id="anime-js"><strong><a href="https://animejs.com/" rel="noreferrer nofollow noopener">anime.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/anime.gif" class="kg-image" alt="anime" width="738" height="276" loading="lazy"><figcaption>anime.js</figcaption></figure><p>Uma das melhores bibliotecas de animação disponíveis, a Anime.js é flexível e simples de usar. É a ferramenta perfeita para te ajudar a adicionar alguma animação elegante ao teu projecto.</p><p>Anime.js funciona bem com propriedades CSS, SVG, atributos DOM e objetos do JavaScript e pode ser facilmente integrada nas tuas aplicações.</p><p>Como programador, é importante ter um bom portfolio. A primeira impressão que as pessoas têm do teu portfolio ajuda a decidir se és contratado ou não. Assim, que melhor ferramenta do que esta biblioteca para dar vida ao teu portfólio? Não só melhorará o teu site, mas também ajudará a demostrar habilidades reais.</p><p>Vê esta demonstração no Codepen para saber mais:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_XWXoboE" src="https://codepen.io/lelouchb/embed/preview/XWXoboE?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=XWXoboE" title="anime.js advanced staggering demo" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Também podes ver outros projetos fixes no <a href="https://codepen.io/collection/XLebem">Codepen </a>ou <a href="https://animejs.com/documentation/">ler a documentação aqui</a> (em inglês). </p><h1 id="screenfull-js"><strong><a href="https://github.com/sindresorhus/screenfull.js">Screenfull.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-29.png" class="kg-image" alt="image-29" width="390" height="101" loading="lazy"><figcaption>screenfull.js</figcaption></figure><p>Encontrei esta biblioteca enquanto procurava uma maneira de implementar uma característica de <em>full-screen</em> no meu projecto.</p><p>Se também precisares de uma característica de <em>full-screen</em>, recomendo usares esta biblioteca em vez da <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API">Fullscreen API</a> devido à sua eficiência nos vários navegadores (ainda que seja construída sobre ela).</p><p>É tão pequena que nem vais reparar no seu tamanho – apenas cerca de 0.7kB zipada.</p><p>Experimenta a demo ou lê a <a href="https://github.com/sindresorhus/screenfull.js">documentação</a> (em inglês), para saber mais.</p><h1 id="moment-js"><strong><a href="https://momentjs.com/">Moment.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-18.png" class="kg-image" alt="image-18" width="348" height="284" loading="lazy"><figcaption>Moment.js</figcaption></figure><p>Trabalhar com data e hora dá bastante trabalho, especialmente com chamadas de API, fusos horários diferentes, idiomas locais e assim por diante. Moment.js pode ajudar-te a resolver alguns problemas, seja a manipular, a validar, a analisar ou a formatar datas e tempo.</p><p>Existem vários métodos que podem ser úteis nos teus projetos. Por exemplo, eu usei o método <code>.fromNow()</code> num dos meus projetos do blog para mostrar a hora em que o artigo foi publicado.</p><pre><code class="language-javascript">const moment = require('moment'); 

relativeTimeOfPost = moment([2019, 07, 13]).fromNow(); 
// a year ago

</code></pre><p>Embora não o utilize com muita frequência, sou fã do seu apoio à internacionalização. Por exemplo, podemos personalizar o resultado acima usando o método <code>.locale()</code>.</p><pre><code class="language-javascript">// Francês
moment.locale('fr');
relativeTimeOfPostInFrench = moment([2019, 07, 13]).fromNow(); 
//il y a un an

// Espanhol
moment.locale('es');
relativeTimeOfPostInSpanish = moment([2019, 07, 13]).fromNow(); 
//hace un año</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ezgif.com-video-to-gif.gif" class="kg-image" alt="ezgif.com-video-to-gif" width="600" height="251" loading="lazy"><figcaption>Página inicial do Moment.js</figcaption></figure><p>Lê a <a href="https://momentjs.com/">documentação</a> aqui (em inglês).</p><p>Nota: também podes querer explorar alternativas, como <a href="https://day.js.org/">Day.js</a> ou <a href="https://date-fns.org/">date-fns</a>.</p><h1 id="hammer-js"><strong><a href="http://hammerjs.github.io/">Hammer.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ezgif.com-video-to-gif-2.gif" class="kg-image" alt="ezgif.com-video-to-gif-2" width="600" height="391" loading="lazy"><figcaption>Hammer.js</figcaption></figure><p>Hammer.js é uma biblioteca do JavaScript que te permite adicionar gestos multitoque nas tuas aplicações para a Web. </p><p>Recomendo esta biblioteca para adicionar um pouco de diversão aos teus componentes. Aqui fica um exemplo, para poderes experimentar. Basta tocar com o rato ou caneta no local onde está escrito "Run Pen" ou clicar na div cinza.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_abdPOPj" src="https://codepen.io/lelouchb/embed/preview/abdPOPj?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=abdPOPj" title="RecognizeWith Hammer.js example" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Ela consegue reconhecer gestos feitos à mão, através do rato ou pointerEvents. Para utilizadores do jQuery, recomendo usar o <a href="http://hammerjs.github.io/jquery-plugin/">plug-in do jQuery</a>.</p><pre><code>$(element).hammer(options).bind("pan", myPanHandler);</code></pre><p>Lê a <a href="http://hammerjs.github.io/getting-started/">documentação aqui</a> (em inglês).</p><h1 id="masonry"><strong><a href="https://masonry.desandro.com/">Masonry</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-20.png" class="kg-image" alt="image-20" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/image-20.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/05/image-20.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/05/image-20.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-20.png 1898w" sizes="(min-width: 720px) 720px" width="1898" height="885" loading="lazy"><figcaption>Masonry</figcaption></figure><p>A Mansonry é uma biblioteca do JavaScript de layout de grade. É maravilhosa e uso-a em muitos dos meus projectos. Suporta elementos de grade simples e a sua colocação de acordo com o espaço vertical disponível, semelhante ao que um construtor faria para encaixar pedras ou blocos para a construção de uma parede.</p><p>Podes usar essa biblioteca para m0strar os teus diferentes projectos numa luz diferente. Usa-a com cartas, imagens, modais, entre outros.</p><p>Aqui está um exemplo simples, para mostrar a magia em ação. Não é propriamente magia, mas demonstra como o layout muda conforme o <strong>zoom in</strong> da página web.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ezgif.com-crop.gif" class="kg-image" alt="ezgif.com-crop" width="600" height="274" loading="lazy"></figure><p>Aqui está o código do exemplo acima:</p><pre><code>var elem = document.querySelector('.grid');
var msnry = new Masonry( elem, {
  itemSelector: '.grid-item',
  columnWidth: 400
});

var msnry = new Masonry( '.grid');
</code></pre><p>Aqui está uma demonstração interessante no Codepen:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_qBbLdLQ" src="https://codepen.io/lelouchb/embed/preview/qBbLdLQ?default-tabs=html%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=qBbLdLQ" title="Masonry - imagesLoaded progress, vanilla JS" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Verifica estes projectos:</p><ul><li><a href="https://halcyon-theme.tumblr.com/">https://halcyon-theme.tumblr.com/</a></li><li><a href="https://tympanus.net/Development/GridLoadingEffects/index.html">https://tympanus.net/Development/GridLoadingEffects/index.html</a></li><li><a href="https://www.erikjo.com/work">https://www.erikjo.com/work</a></li></ul><h1 id="d3-js"><strong><a href="https://d3js.org/">D3.js</a></strong></h1><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-30.png" class="kg-image" alt="image-30" width="400" height="400" loading="lazy"></figure><p>Se és um programador obcecado por dados, então esta biblioteca é para ti. Ainda tenho de descobrir uma biblioteca que manipule tão eficazmente e de maneira tão bonita os dados como a D3. Com mais de 92 mil estrelas no <br>GitHub, a D3 é a biblioteca de visualização de dados preferida de muitos programadores.</p><p>Recentemente, utilizei a D3 para visualizar dados do COVID-19 e o <a href="https://github.com/CSSEGISandData/COVID-19">Repositório de dados do Centro de Ciência e Engenharia de Sistemas (CSSE) da Universidade Johns Hopkins no GitHub</a>. Foi um projecto muito interessante. Se estás a pensar em fazer algo semelhante, sugiro experimentares a D3.js.</p><p>Lê mais sobre essa biblioteca <a href="https://github.com/d3/d3/wiki">aqui</a> (em inglês).</p><h1 id="slick"><strong><a href="https://kenwheeler.github.io/slick/">slick</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-23.png" class="kg-image" alt="image-23" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/image-23.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/05/image-23.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-23.png 1520w" sizes="(min-width: 720px) 720px" width="1520" height="578" loading="lazy"><figcaption>Slick</figcaption></figure><p>A Slick é totalmente responsiva, com integração de <em>swipe</em>, <em>loop</em> infinito e muito mais. Tal como mencionado na sua página oficial, é mesmo o último carrossel de que precisas.</p><p>Tenho usado esta biblioteca por algum tempo, o que me permite poupar muito tempo. Com apenas algumas linhas de código, podes adicionar várias características ao teu carrossel.</p><pre><code class="language-js">$('.autoplay').slick({
  slidesToShow: 3,
  slidesToScroll: 1,
  autoplay: true,
  autoplaySpeed: 2000,
});</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ezgif.com-video-to-gif-2-.gif" class="kg-image" alt="ezgif.com-video-to-gif-2-" width="600" height="426" loading="lazy"><figcaption>Autoplay</figcaption></figure><p>Verifica as demonstrações <a href="https://kenwheeler.github.io/slick/">aqui</a> (página em inglês).</p><h1 id="popper-js"><strong><a href="https://popper.js.org/">Popper.js</a></strong></h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-25.png" class="kg-image" alt="image-25" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/05/image-25.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/05/image-25.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/05/image-25.png 1200w" sizes="(min-width: 720px) 720px" width="1200" height="627" loading="lazy"><figcaption>Popper.js</figcaption></figure><p>A Popper.js é uma biblioteca JavaScript leve, de cerca de 3kB, sem dependências e que fornece um mecanismo de posicionamento confiável e extensível, que podes usar para garantir que todos os teus elementos <em>popper</em> estejam posicionados no lugar certo.</p><p>Investir tempo para configurar elementos <em>popper</em> pode não parecer importante, mas essas são as pequenas coisas que te distinguem enquanto programador. C0m um espaço tão pequeno, ela nem sequer ocupa tanto espaço assim.</p><p>Lê a <a href="https://popper.js.org/docs/v2/">documentação aqui</a> (em inglês).</p><h1 id="conclus-o"><strong>Conclusão</strong></h1><p>Como programador, é importante possuir e usar as bibliotecas do JavaScript correctas. Tornar-te-á mais produtivo e tornará tua programação muito mais fácil e rápida. No fim de contas, és tu que decides qual a biblioteca que preferes usar, de acordo com as tuas necessidades.</p><p>Estas são as 10 bibliotecas do JavaScript que podes experimentar e começar a usar nos teus projectos hoje. Que outras bibliotecas do JavaScript utilizas? Gostarias de ler outro artigo parecido a este? Podes enviar uma mensagem ao autor pelo <a href="https://twitter.com/noharashutosh">Twitter</a> e informá-lo disso. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar seu primeiro gráfico em JavaScript com o JSCharting ]]>
                </title>
                <description>
                    <![CDATA[ Quando se está começando como desenvolvedor JavaScript iniciante, acho que é importante buscar projetos interessantes. Assim, você pode se divertir enquanto aprende e provavelmente encontrará uma área de especialização que seja do seu agrado. Como se costuma dizer, "se você ama o que faz, nunca trabalhará um dia sequer em ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-seu-primeiro-grafico-em-javascript-com-o-jscharting/</link>
                <guid isPermaLink="false">65568961f2994303ed34426e</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Filipe Virgínio Vital Torres Barbosa ]]>
                </dc:creator>
                <pubDate>Tue, 14 May 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/first-javascript-chart-using-csv-jscharting-fit.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-make-your-first-javascript-chart/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to make your first JavaScript chart with JSCharting</a>
      </p><p>Quando se está começando como desenvolvedor JavaScript iniciante, acho que é importante buscar projetos interessantes. Assim, você pode se divertir enquanto aprende e provavelmente encontrará uma área de especialização que seja do seu agrado.</p><p>Como se costuma dizer, <em>"se você ama o que faz, nunca trabalhará um dia sequer em sua vida"</em>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/not-suited-for-work.gif" class="kg-image" alt="not-suited-for-work" width="480" height="266" loading="lazy"><figcaption>Fonte: giphy.com</figcaption></figure><p>Neste artigo, apresentarei a visualização de dados de front-end, que é minha paixão pessoal. Talvez ela também se torne sua paixão!</p><p>Os momentos mais gratificantes para mim como desenvolvedor são quando posso ver ou experimentar os resultados do que criei. É muito gratificante criar um gráfico que revela insights interessantes sobre seus dados ou uma experiência interativa que ajuda a explorar detalhes de um conjunto de dados exclusivo. Quanto mais significativo for o resultado, mais gratificante será a sensação.</p><p>No entanto, percebi que a quantidade de trabalho que você dedica a um projeto não está necessariamente relacionada à sensação de realização – às vezes, a sensação é ótima mesmo quando foi relativamente fácil.</p><p>Com o tempo, você encontrará ferramentas que o ajudarão a ser mais eficiente e, às vezes, você moverá montanhas com pouco esforço. Há muitas bibliotecas de gráficos e ferramentas disponíveis na área de visualização de dados. Com as ferramentas certas, você criará novos gráficos com pouco esforço, independentemente do tipo de gráfico de que precisar. Pessoalmente, acho que a visualização dos dados gera uma grande recompensa pelo seu investimento de tempo e esforço.</p><p>Neste tutorial, você usará várias ferramentas para obter dados pela Internet, processará esses dados e desenhará um belo gráfico que pode ser visualizado em qualquer navegador moderno. Você pode clicar nos links abaixo para baixar o código de exemplo de cada etapa individualmente, visualizar todos no <strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article">GitHub</a></strong></strong>, ou baixar todas as etapas de uma só vez aqui: <strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/all-steps.zip">all-steps.zip</a>.</strong></strong></p><h2 id="o-resultado"><strong>O resultado</strong></h2><p>Ao final do tutorial, você criará este gráfico interativo orientado por dados. Você aprenderá a obter dados pela Internet, a processá-los e a criar um gráfico com esses dados. Você também poderá criar seus próprios gráficos do zero.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/javascript-line-chart.png" class="kg-image" alt="javascript-line-chart" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/javascript-line-chart.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/javascript-line-chart.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/javascript-line-chart.png 1282w" sizes="(min-width: 720px) 720px" width="1282" height="536" loading="lazy"><figcaption>Gráfico de linha interativo feito em JavaScript</figcaption></figure><p>Depois de processar os dados e fazer o gráfico, você também aprenderá a fazer ajustes no gráfico, incluindo a modificação da legenda padrão, a ativação de pontos de foco (em inglês, <em>crosshairs</em>) no eixo x com dicas (em inglês, <em>tooltips</em>) e a aplicação de anotações de texto para adicionar contexto e outras informações ao gráfico.</p><h2 id="as-ferramentas"><strong>As ferramentas</strong></h2><p>Para começar, use um navegador da internet como o que você provavelmente está usando para ler este artigo. Recomendo o Chrome, pois ele oferece uma ótima experiência e ferramentas integradas para desenvolvedores.</p><p>Em seguida, você precisará de um editor de texto. Algo simples como o bloco de notas funcionará. No entanto, sugiro usar um editor de código mais avançado, como o VS Code, pois esse é um ambiente no qual você passará muito tempo. Ele proporcionará a você uma experiência de programação mais conveniente e agradável, além de tornar a escrita em HTML5, CSS e JavaScript mais agradável aos olhos. O mais importante é que, se você esquecer uma citação ou uma vírgula em algum lugar, um editor de código poderá ajudá-lo a encontrar o erro.</p><p>Este artigo pode ajudá-lo a <a href="https://www.freecodecamp.org/news/how-to-choose-a-javascript-code-editor/">escolher o melhor editor de código em JavaScript para o desenvolvimento para a Web</a> (texto em inglês).</p><p>Você usará a biblioteca de gráficos JSCharting para desenhar e adicionar a funcionalidade interativa ao gráfico automaticamente. Não serão necessárias outras bibliotecas do JavaScript, como o jQuery, ou plataformas de front-end, como o React e o Angular (comumente usadas em projetos de sites).</p><h3 id="por-que-jscharting"><strong>Por que JSCharting?</strong></h3><p>O JSCharting é uma biblioteca de gráficos em JavaScript que pode desenhar muitos tipos diferentes de gráficos usando SVG. Ela é fácil de usar e de começar a aprender, sendo, portanto, é uma boa opção para este tutorial. A API (Interface de Programação de Aplicativos, ou seja, as opções e configurações necessárias para criar gráficos) torna as coisas difíceis mais simples e é uma boa opção para fazer experiências com visualizações de dados.</p><p>Você pode usar o JSCharting gratuitamente para uso pessoal e comercial com a marca incluída.</p><p>Você pode criar gráficos responsivos com o JSCharting por meio de algumas etapas simples:</p><ul><li>Defina uma tag <code>&lt;div&gt;</code> no HTML com um ID único.</li><li>Forneça essa id, os dados e quaisquer outras opções ao chamar <code>JSC.Chart()</code> no arquivo JavaScript.</li></ul><p>É isso. O JSC desenhará um gráfico de aparência profissional preenchendo essa tag div com elementos visuais em SVG. O gráfico será responsivo e interativo sem nenhum esforço extra.</p><h2 id="os-dados"><strong>Os dados</strong></h2><p>Você usará um arquivo de dados fornecido pelo NCHS (National Center for Health Statistics, o Centro Nacional de Estatísticas em Saúde) que lista a expectativa de vida histórica de homens e mulheres nos EUA.</p><p>Você pode encontrar esses dados aqui: <a href="https://data.cdc.gov/resource/w9j2-ggv5.csv">https://data.cdc.gov/resource/w9j2-ggv5.csv</a>.</p><p>Esse arquivo CSV contém dados que categorizam as expectativas de vida por ano, raça e sexo. Você usará alguns desses dados para desenhar uma simples linha de tendência para homens e mulheres nos últimos 100 anos.</p><p>O arquivo CSV (de <em>Comma Separated Values</em>, que significa valores separados por vírgula) é um formato muito bom para transmitir dados pela Internet. É compacto, legível por humanos e você pode abri-lo diretamente no Excel, o que também é ótimo.</p><p>Portanto, sem mais delongas, vamos começar.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/readycat.gif" class="kg-image" alt="readycat" width="480" height="452" loading="lazy"><figcaption>Fonte: giphy.com</figcaption></figure><h2 id="passo-1-adicionar-um-gr-fico-em-branco"><strong>Passo 1 – </strong>adicionar um gráfico em branco</h2><p>O primeiro arquivo zip contém um ponto de partida em branco que pode ser preenchido à medida que avançamos. Se você se perder ou ficar confuso, ou se quiser pular adiante, o arquivo zip no final ou ao longo de cada seção o deixará atualizado.</p><p>Se desejar fazer o download de todos os arquivos de uma só vez, pegue o arquivo <strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/all-steps.zip">all-steps.zip</a></strong></strong><em><em>.</em></em></p><h3 id="step1-a-zip"><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step1-a.zip">step1-a.zip</a></strong></h3><p>Esse arquivo zip contém os seguintes arquivos:</p><ul><li><code>index.html</code></li><li><code>js/index.js</code></li></ul><p>O arquivo <code>.html</code> está vazio, exceto por algum código padrão que o torna um arquivo válido, enquanto o arquivo <code>.js</code> está completamente vazio.</p><p>A primeira coisa a fazer é adicionar alguns scripts ao arquivo HTML da página da Web. Normalmente, as pessoas sugerem adicionar tags <code>&lt;script&gt;</code> dentro das tags <code>&lt;head&gt;</code>. No entanto, para scripts que afetam o conteúdo HTML, geralmente é melhor adicioná-los após o fechamento da tag <code>&lt;/body&gt;</code>.</p><p>Essa técnica carrega todo o HTML no DOM antes de executar qualquer JavaScript. O gráfico precisa do HTML carregado antes de poder desenhar nele. O DOM (de <em>Document Object Model</em> – em português, Modelo de Objeto de Documentos) é uma representação de seu código HTML na memória do navegador. Depois que o HTML é carregado no DOM, o navegador pode exibi-lo e o JavaScript pode interagir com ele.</p><p>Comece adicionando a biblioteca JSCharting ao arquivo HTML. Abra o arquivo <code>index.html</code> no editor de sua preferência. Em seguida, adicione uma tag de script para incluir o JSCharting após a tag de fechamento <code>&lt;/body&gt;</code>. O código resultante na parte inferior do arquivo deve ter a seguinte aparência:</p><pre><code class="language-html">&lt;/body&gt;
&lt;script src="https://code.jscharting.com/2.9.0/jscharting.js"&gt;&lt;/script&gt;
&lt;/html&gt;</code></pre><p>O URL dessa biblioteca aponta para uma CDN (<em>Content Delivery Network</em> – em português, rede de distribuição de conteúdo). Ela hospeda o código do gráfico e torna conveniente adicionar rapidamente a biblioteca a qualquer página HTML para criar protótipos de gráficos e fazer experimentos. Você também pode <a href="https://jscharting.com/download/">baixar</a> e usar a biblioteca localmente ou usar o pacote npm em seu projeto, mas a CDN não exige nenhuma etapa adicional.</p><p>Em seguida, usando a mesma técnica, adicione outra tag de script fazendo referência ao seu arquivo JavaScript em branco. Adicione esse script após o script de <code>jscharting.js</code> para que tenha a seguinte aparência:</p><pre><code class="language-html">&lt;/body&gt;
&lt;script src="https://code.jscharting.com/2.9.0/jscharting.js"&gt;&lt;/script&gt;
&lt;script src="js/index.js"&gt;&lt;/script&gt;
&lt;/html&gt;</code></pre><p>Ótimo. Estamos quase prontos para desenhar um gráfico em branco. A última coisa que você precisa fazer é adicionar uma tag <code>&lt;div&gt;</code> dentro do arquivo HTML para definir onde queremos que este gráfico seja desenhado.</p><p>Adicione este código HTML dentro das tags <code>&lt;body&gt;</code>.</p><pre><code class="language-html">&lt;body&gt;
    &lt;div id="chartDiv" style="width:50%; height:300px; margin:0 auto;"&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre><p>A div deve ter um id para que você possa informar ao gráfico em qual div deve ser desenhada. Nesse caso, o id é <code>chartDiv</code>.</p><p>Você pode notar o atributo style da tag <code>&lt;div&gt;</code>. Ele faz com que a div tenha 50% da largura da janela e 300 pixels de altura. O estilo de margem <code>margin: 0 auto;</code> centraliza a div na página. O gráfico será preenchido independentemente do tamanho da div, portanto, alterar o tamanho da div é uma boa maneira de controlar o tamanho do gráfico.</p><p>Está tudo pronto com o arquivo HTML. Abra o arquivo <code>index.js</code> e adicione um gráfico em branco a essa página escrevendo o seguinte código, que inclui a div id <code>chartDiv</code>:</p><pre><code class="language-javascript">JSC.Chart('chartDiv', {});</code></pre><p>Abra o arquivo <code>index.html</code> em um navegador (arraste e solte o arquivo em um navegador da Web como o Chrome).</p><p>Ainda não há muito para ver, mas você pode notar um pequeno logotipo da JSC nesta página. Isso indica que um gráfico está conectado e sendo desenhado.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/jscharting-brand.png" class="kg-image" alt="jscharting-brand" width="104" height="63" loading="lazy"><figcaption>A logo do JSCharting mostra que o gráfico está funcionando</figcaption></figure><p><strong><strong><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step1-b.zip">step1-b.zip</a></strong></strong></strong></strong></p><h2 id="passo-2-brinque-um-pouco-com-o-gr-fico"><strong>Passo 2 – b</strong>rinque um pouco com o gráfico</h2><p>Para testar, vamos adicionar alguns valores para o gráfico visualizar e ver como ele funciona.</p><p>Voltando ao arquivo <code>index.js</code>, substitua o conteúdo pelo código a seguir, que adiciona mais opções ao gráfico.</p><pre><code class="language-javascript">JSC.Chart('chartDiv', {
   type: 'horizontal column',
   series: [
      {
         points: [
            {x: 'Apples', y: 50},
            {x: 'Oranges', y: 42}
         ]
      }
   ]
});</code></pre><p>Agora, atualize (F5) a janela do navegador onde a página <code>index.html</code> está carregada.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/horizontal-column-chart.png" class="kg-image" alt="horizontal-column-chart" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/horizontal-column-chart.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/horizontal-column-chart.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/horizontal-column-chart.png 1064w" sizes="(min-width: 720px) 720px" width="1064" height="454" loading="lazy"><figcaption>Gráfico de barras horizontais com uma série e dois pontos</figcaption></figure><p>Muito bom! Você acabou de criar seu primeiro gráfico usando JavaScript.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/yeah-1.gif" class="kg-image" alt="yeah-1" width="335" height="230" loading="lazy"><figcaption>Fonte: giphy.com</figcaption></figure><p>Você criou um gráfico de barras ao definir a opção de tipo de gráfico como <code>'horizontal column'</code>. Se você preferir uma coluna vertical, defina o valor como <code>'column'</code>. Você também adicionou uma série com dois pontos ao gráfico para Maçãs e Laranjas (<em>Apples</em> e <em>Oranges</em>, em inglês, respectivamente).</p><p>Todos os dados do gráfico são compostos de séries e pontos. Uma série é simplesmente um grupo de pontos de dados. Os gráficos podem conter uma ou mais séries de dados. Os pontos de dados consistem em valores que mapeiam os eixos x e y. Os pontos também podem incluir muitas outras variáveis e valores descritivos.</p><p>O exemplo acima contém apenas uma série. Agora vamos dar uma olhada nas opções para um gráfico com duas séries. Substitua o conteúdo do arquivo JavaScript por este código.</p><pre><code class="language-javascript">JSC.Chart('chartDiv', {
   type: 'horizontal column',
   series: [
      {
         name:'Andy',
         points: [
            {x: 'Apples', y: 50},
            {x: 'Oranges', y: 32}
         ]
      },{
         name:'Anna',
         points: [
            {x: 'Apples', y: 30},
            {x: 'Oranges', y: 22}
         ]
      }
   ]
});</code></pre><p>Ao atualizar da janela do navegador será exibido este gráfico.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/horizontal-column-cluster.png" class="kg-image" alt="horizontal-column-cluster" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/horizontal-column-cluster.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/horizontal-column-cluster.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/horizontal-column-cluster.png 1065w" sizes="(min-width: 720px) 720px" width="1065" height="459" loading="lazy"><figcaption>Gráfico de barras horizontais com duas séries</figcaption></figure><p>As opções do gráfico são semelhantes. Ainda é um gráfico de barras, mas dessa vez há um objeto extra no array de séries. &nbsp;Também adicionamos propriedades de nome para cada série para que o gráfico possa identificá-las na legenda.</p><p>Se estiver interessado em criar gráficos diferentes, como gráficos de radar, gráficos de área, gráficos de pizza, gráficos de Gantt ou até mesmo gráficos de mapa de calor de calendário, dê uma olhada na <a href="https://jscharting.com/examples/chart-types/">galeria de exemplos do JSCharting</a> e o código-fonte (opções de gráfico) usado para criar esses gráficos. Você pode aprender rapidamente a usar outros recursos de gráficos copiando os exemplos disponíveis.</p><p><strong><strong><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step2.zip">step2.zip</a></strong></strong></strong></strong></p><h2 id="passo-3-prepare-os-dados"><strong>Passo 3 – prepare os dados</strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/data.gif" class="kg-image" alt="data" width="448" height="352" loading="lazy"><figcaption>Fonte: giphy.com</figcaption></figure><p>O formato de dados CSV é exatamente isso: valores separados por vírgula. O arquivo contém linhas e cada linha representa um registro ou entrada. Normalmente, a primeira linha de valores contém os nomes de cada valor separado por vírgula (coluna). As linhas subsequentes contêm os valores propriamente ditos.</p><pre><code>name,age
chris,26
mike,34</code></pre><p>O CSV é legível por humanos, mas há variações desse formato. Às vezes, se os valores contiverem vírgulas (por exemplo, endereços de correspondência), o formato não funcionará como está, de modo que cada valor também é envolvido por aspas. Dessa forma, as vírgulas dentro das aspas são ignoradas e o formato ainda pode funcionar usando apenas as vírgulas fora das aspas para separar os valores.</p><pre><code>"name","age","parents"
"Chris","26","Gregory, Mary"
"Mike","34","David, Sarah"</code></pre><p>Os valores também podem ser separados usando um caractere diferente, como tabulações no lugar de vírgulas.</p><p>Não vamos, porém, nos prender a minúcias. O JSCharting fornece várias ferramentas que ajudam nesse processo e usaremos uma delas para não nos preocuparmos com o formato do arquivo CSV e convertê-lo em JSON (JavaScript Object Notation). O resultado será um array de objetos. Cada objeto representa uma linha com propriedades nomeadas. A primeira linha do arquivo CSV é usada para definir os nomes dessas propriedades.</p><p>Este é o url dos dados nos quais estamos interessados: <a href="https://data.cdc.gov/resource/w9j2-ggv5.csv">https://data.cdc.gov/resource/w9j2-ggv5.csv</a>.</p><p>Você pode clicar para fazer o download e abri-lo no Excel.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-28.png" class="kg-image" alt="image-28" width="479" height="330" loading="lazy"><figcaption>Arquivo CSV aberto no Excel</figcaption></figure><p>No entanto, você fará o download e acessará esses dados CSV em tempo real usando o código JavaScript. O código abaixo pode ser um pouco confuso no início, mas é curto e você pode reutilizá-lo para obter qualquer arquivo CSV, texto ou JSON pela internet de modo programático. É semelhante à antiga tecnologia AJAX, mas muito mais simples de usar.</p><p>Mais uma vez, substitua o conteúdo do arquivo <code>index.js</code> pelo seguinte:</p><pre><code class="language-javascript">fetch('https://data.cdc.gov/resource/w9j2-ggv5.csv')
   .then(function (response) {
      return response.text();
   })
   .then(function (text) {
	csvToSeries(text);
   })
   .catch(function (error) {
      //Something went wrong
      console.log(error);
   });

function csvToSeries(text) {
   console.log(text);
}</code></pre><p>Por que é tão complicado? É porque quando você solicita um arquivo, ele não fica disponível imediatamente. Há um atraso e você precisa aguardar a chegada do arquivo. Portanto, primeiro você solicita o arquivo de outro site usando <code>fetch()</code>.</p><pre><code class="language-javascript">fetch('https://data.cdc.gov/resource/w9j2-ggv5.csv')</code></pre><p>Em seguida, o código dentro da função de argumento <code>then(...)</code> é chamado com a resposta quando ela chega. Essa função converte a resposta em texto e a retorna, que passa o resultado para a próxima função do método <code>then()</code>.</p><pre><code class="language-javascript">.then(function (response) {
	return response.text();
})</code></pre><p>A próxima função do método <code>then(...)</code> chama a função <code>csvToSeries()</code> e passa o texto como argumento.</p><pre><code class="language-javascript">.then(function (text) {
	csvToSeries(text);
})</code></pre><p>Na função do método <code>catch()</code>, você pode especificar o que fazer se algo der errado. Por exemplo, talvez a internet não esteja disponível ou o URL não esteja correto.</p><pre><code class="language-javascript">.catch(function (error) {
	//Something went wrong
	console.log(error);
});</code></pre><p>Nesse caso, o erro é enviado para o console.</p><p>Na função <code>csvToSeries()</code>, passamos esse texto para o console para inspeção.</p><pre><code class="language-javascript">function csvToSeries(text) {
   console.log(text);
}</code></pre><p><strong>Observação<strong>:</strong> </strong>a função <code>fetch()</code> nativa não é compatível com o Internet Explorer 11. Se você também quiser oferecer suporte a esse navegador, poderá usar a função <code>JSC.fetch()</code> que vem com o JSCharting. Ela oferece a mesma funcionalidade, mas acrescenta suporte adicional ao IE11.</p><p>Arraste o arquivo <code>index.html</code> para uma janela do navegador (ou atualize a página se já estiver aberta) e pressione F12. Isso abrirá a janela DevTools do navegador Chrome. Por padrão, a metade inferior da janela do DevTools mostrará a saída do console. É para lá que o texto é enviado quando você executa códigos usando:</p><pre><code class="language-javascript">console.log(text);</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0.png" class="kg-image" alt="pasted-image-0" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/pasted-image-0.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0.png 858w" width="858" height="278" loading="lazy"><figcaption>Saída da janela do console</figcaption></figure><p>Você também pode colar ou escrever código nessa janela do console para executá-lo. Tente colar todo o trecho de código acima na janela do console (ao lado do caractere &gt;) e pressione Enter. Você perceberá que obtém o mesmo resultado na saída da janela do console. Isso pode ser útil para testar uma linha de código e fazer experimentos.</p><p><strong><strong><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step3-a.zip">step3-a.zip</a></strong></strong></strong></strong></p><p>Neste ponto, você recuperou o texto do arquivo CSV pela internet e o enviou ao console para provar que ele funciona. Agora podemos começar a trabalhar com ele.</p><p>Vamos dar uma olhada nesse arquivo de dados para ter uma ideia do que há nele: <a href="https://data.cdc.gov/resource/w9j2-ggv5.csv">https://data.cdc.gov/resource/w9j2-ggv5.csv</a></p><p>Usei o Excel para classificar as linhas pela coluna do ano para analisar as linhas de dados de um único ano.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-27.png" class="kg-image" alt="image-27" width="494" height="233" loading="lazy"><figcaption>Os dados do CSV, ordenados por ano.</figcaption></figure><p>Cada ano contém 9 linhas com dados baseados em raça e sexo. Estamos interessados apenas nos valores destacados de homens e mulheres de todas as raças para cada ano. Você criará duas séries com base nas linhas destacadas. Uma série para valores femininos e outra para valores masculinos.</p><p>Agora que você tem uma ideia do que precisa acontecer, vamos começar.</p><p>Primeiro, vamos usar a função <code>JSC.csv2Json()</code> para converter o texto no formato JSON e passá-lo para o console para ver o que ele faz.</p><p>Atualize a função <code>csvToSeries()</code> com o seguinte código:</p><pre><code class="language-javascript">function csvToSeries(text) {
   let dataAsJson = JSC.csv2Json(text);
   console.log(dataAsJson)
}</code></pre><p>Atualize o navegador para ver a saída atualizada do console.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-29.png" class="kg-image" alt="image-29" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-29.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-29.png 859w" width="859" height="356" loading="lazy"><figcaption>Dados do CSV convertidos para JSON usando a função utilitária JSC.csv2Json()</figcaption></figure><p>O console mostra um array de 1062 registros. Este é um desses registros:</p><pre><code class="language-json">{year: 1900, race: "All Races", sex: "Both Sexes", average_life_expectancy: 47.3, mortality: 2518}</code></pre><p><strong>Observação<strong>:</strong></strong> o console pode exibir arrays e objetos para inspeção e você pode expandir e recolher seções no console para explorar detalhes.</p><p>O nome da propriedade <code>average_life_expectancy</code> é um pouco longo, mas você precisará usá-lo. Para evitar digitá-lo mais de uma vez, defina uma constante para armazenar esse nome. Quando você precisar usar essa propriedade, basta escrever o nome da constante <code>lifeExp</code>. Ela terá esta aparência, <code>row[lifeExp]</code>, em vez de <code>row.average_life_expectancy</code>.</p><p>Adicione esta linha na parte superior da função <code>csvToSeries()</code>.</p><pre><code class="language-javascript">function csvToSeries(text) {
	const lifeExp = 'average_life_expectancy';
	...</code></pre><p>Você pode processar esses dados usando JavaScript simples. O resultado final que queremos são duas séries com pontos de dados que incluem um ano e a expectativa de vida para cada ponto.</p><p>Atualize a função <code>csvToSeries()</code> com o seguinte código:</p><pre><code class="language-javascript">function csvToSeries(text) {
	const lifeExp = 'average_life_expectancy';
	let dataAsJson = JSC.csv2Json(text);
	let male = [], female = [];
	dataAsJson.forEach(function (row) {
		 //add either to male, female, or discard.
		console.log(row);
	});
}</code></pre><p>Ele define arrays para pontos de dados masculinos e femininos. Em seguida, ele chama a função array <code>dataAsJson.forEach()</code> passando uma função de retorno de chamada (<em>callback</em>) <code>function(row){...}</code> como argumento. A função <code>forEach()</code> executará a função de retorno de chamada para cada item no array <code>dataAsJson</code>. Por enquanto, chamaremos apenas <code>console.log(row)</code> em cada linha que a função de retorno de chamada encontrar.</p><p>Atualize o navegador e inspecione a saída do console.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/7923058b-f96d-4ba5-b94b-90596f035711.png" class="kg-image" alt="7923058b-f96d-4ba5-b94b-90596f035711" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/7923058b-f96d-4ba5-b94b-90596f035711.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/7923058b-f96d-4ba5-b94b-90596f035711.png 848w" width="848" height="353" loading="lazy"><figcaption>Cada objeto de linha que a função de retorno de chamada encontrou</figcaption></figure><p>Vamos adicionar alguma lógica para filtrar os dados que desejamos e registrar o resultado na janela do console. Substitua a função <code>csvToSeries()</code> por este código.</p><pre><code class="language-javascript">function csvToSeries(text) {
	const lifeExp = 'average_life_expectancy';
	let dataAsJson = JSC.csv2Json(text);
	let male = [], female = [];
	dataAsJson.forEach(function (row) {
		 //add either to male, female, or discard.
		if (row.race === 'All Races') {
			if (row.sex === 'Male') {
				male.push({x: row.year, y: row[lifeExp]});
			} else if (row.sex === 'Female') {
				female.push({x: row.year, y: row[lifeExp]});
			}
		}
	});
    console.log([male, female]);
}</code></pre><p>Dentro da função de retorno de chamada, você decide se a linha é de interesse e a utiliza. Caso contrário, você a descarta.</p><pre><code class="language-javascript">if (row.race === 'All Races') {
	if (row.sex === 'Male') {
		//add data to male array
		male.push({x: row.year, y: row[lifeExp]});
	} else if (row.sex === 'Female') {
		//add data to female array
		female.push({x: row.year, y: row[lifeExp]});
	}
}</code></pre><p>A lógica verifica se o valor <code>row.race</code> é igual a 'All Races'. Se for, verifica se a propriedade <code>row.sex</code> é igual a 'Male' ou 'Female'. Se a linha for igual a qualquer uma delas, ele adiciona os dados aos arrays <code>male</code> ou <code>female</code> como um objeto de ponto <code>{x, y}</code>. Observe o uso da constante <code>lifeExp</code> definida acima, que ajuda a encurtar esse código.</p><p>No final, você usou <code>console.log([male, female])</code> para passar as variáveis <em>male</em> e <em>female</em> (masculino e feminino, em inglês) para o console para inspeção e para garantir que o código funcionou conforme o esperado.</p><p>Depois de atualizar o navegador, o console mostra o resultado, que são dois arrays, cada um com 118 pontos de dados que abrangem os anos de 1900 a 2017.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0--1-.png" class="kg-image" alt="pasted-image-0--1-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/pasted-image-0--1-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0--1-.png 862w" width="862" height="356" loading="lazy"><figcaption>Os arrays de pontos masculinos e femininos</figcaption></figure><p>Por fim, em vez de passar o resultado para o console, envolva esses pontos de dados em um array de duas séries que o gráfico possa usar diretamente e retorne-os.</p><p>Adicione este código no final da função <code>csvToSeries()</code>:</p><pre><code class="language-javascript">return [
   {name: 'Male', points: male},
   {name: 'Female', points: female}
];</code></pre><p>Se o valor retornado fosse enviado para o console, ele produziria este resultado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0--2-.png" class="kg-image" alt="pasted-image-0--2-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/pasted-image-0--2-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/pasted-image-0--2-.png 852w" width="852" height="356" loading="lazy"><figcaption>Dois objetos de série que o gráfico pode consumir diretamente</figcaption></figure><p>Como você pode ver, a lógica para filtrar as linhas é bastante simples e você pode ajustá-la para obter outros detalhes desse conjunto de dados.</p><p>Para saber mais sobre como lidar com arquivos CSV usando os utilitários do JSCharting, consulte este tutorial. Quando você estiver pronto para um tratamento de dados mais avançado, o utilitário JSC.nest() poderá ser usado para criar séries e pontos a partir de dados JSON com muito pouco código.</p><p><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step3-b.zip"><strong><strong>step3-b.zip</strong></strong></a></p><h2 id="passo-4-juntando-tudo"><strong>Passo 4 – </strong>juntando tudo</h2><p>A seção de manipulação de dados foi a etapa mais difícil, mas só ela permitirá que você manipule e extraia dados de interesse de qualquer arquivo CSV. É aqui que tudo se encaixa e que você terá uma sensação de realização.</p><p>Comece adicionando uma função <code>renderChart()</code> ao final do arquivo <code>index.js</code>. Você passará os dados da série para essa função como um argumento.</p><pre><code class="language-javascript">function renderChart(series){
   JSC.Chart('chartDiv', {
      series: series
   });
}</code></pre><p>Na função do método <code>then()</code> que chama a função <code>csvToSeries()</code>, passe o resultado da série para a função <code>renderChart()</code> para ver o que ela desenha no navegador.</p><pre><code class="language-javascript">.then(function (text) {
	let series = csvToSeries(text);
	renderChart(series);
})</code></pre><p><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step4-a.zip">step4-a.zip</a></strong></strong></p><p>Agora, atualize o navegador. Você deverá ver este gráfico que usa os dados CSV processados na seção anterior. Não é incrível?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart.png" class="kg-image" alt="csv-line-chart" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/csv-line-chart.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/csv-line-chart.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart.png 1378w" sizes="(min-width: 720px) 720px" width="1378" height="615" loading="lazy"><figcaption>Gráfico de linhas mostrando dados CSV filtrados</figcaption></figure><p>Uau, o que aconteceu em 1918? A expectativa de vida caiu significativamente lá. De acordo com a Wikipédia, houve uma pandemia de gripe envolvendo o vírus H1N1 que dizimou uma parte da população mundial. Esse evento infeliz mostra como a visualização de dados fornece insights que você normalmente não obteria apenas observando os números.</p><p>Você criou um gráfico usando o tipo de série de linhas padrão e ele está com boa aparência, mas pode fazer alguns ajustes para melhorá-lo ainda mais.</p><p>Primeiro, adicione um título na parte superior para explicar o que o usuário está vendo e uma anotação na parte inferior do gráfico para dar crédito à fonte dos dados. Atualize a função do construtor <code>JSC.Chart()</code> para passar as seguintes opções:</p><pre><code class="language-javascript">function renderChart(series){
	JSC.Chart('chartDiv', {
		title_label_text: 'Life Expectancy in the United States',
		annotations: [{
			label_text: 'Source: National Center for Health Statistics',
			position: 'bottom left'
		}],
		series: series
	});
}
</code></pre><p>Quando você atualiza o navegador, pode ver o gráfico atualizado.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/line-chart-annotations.png" class="kg-image" alt="line-chart-annotations" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/line-chart-annotations.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/line-chart-annotations.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/line-chart-annotations.png 1245w" sizes="(min-width: 720px) 720px" width="1245" height="569" loading="lazy"><figcaption>Gráfico de linhas com título e anotação para atribuição</figcaption></figure><p>Você adicionou uma anotação com texto do rótulo e uma configuração de posição. Também podemos usar outra anotação para o título, mas foi mais fácil usar o rótulo do título neste exemplo.</p><p>É fácil controlar a posição da anotação usando valores como <code>'top right'</code> ou <code>'inside bottom right'</code>. O valor <code>'inside'</code> significa que a anotação é colocada dentro da área do gráfico onde os dados são desenhados. Este <a href="https://jscharting.com/examples/chart-features/annotation/box-positions/">exemplo de gráfico de posições de caixa</a> demonstra todas as opções de configuração de posição.</p><p>A legenda mostra a soma dos valores de pontos de cada série, mas a soma não é importante para esse conjunto de dados. Você pode reduzir as colunas de legenda para mostrar apenas o ícone e o nome da série usando essa configuração:</p><pre><code class="language-javascript">legend_template: '%icon,%name'</code></pre><p>No entanto, você não precisa realmente usar uma legenda. Será mais limpo se simplesmente rotular as próprias linhas. Você pode desativar a legenda e instruir o gráfico a escrever o nome da série no último ponto de cada série de linhas com essas opções de gráfico:</p><pre><code class="language-javascript">legend_visible: false,
defaultSeries_lastPoint_label_text: '&lt;b&gt;%seriesName&lt;/b&gt;',
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart-labels.png" class="kg-image" alt="csv-line-chart-labels" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/csv-line-chart-labels.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/csv-line-chart-labels.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart-labels.png 1393w" sizes="(min-width: 720px) 720px" width="1393" height="571" loading="lazy"><figcaption>Gráfico de linhas usando rótulos de pontos em vez de uma legenda</figcaption></figure><p>O token<code>'%seriesname'</code> é um dos muitos <a href="https://jscharting.com/tutorials/js-chart-labels/token-reference/#point-tokens">tokens relacionados a pontos</a> que podem ser usados em qualquer texto de rótulo de ponto para mostrar detalhes e cálculos de pontos.</p><p>Por fim, vamos ativar a <em>tooltip </em>do eixo x para mostrar a expectativa de vida masculina e feminina em um determinado ano. Em dispositivos móveis, você pode tocar no gráfico para ver a <em>tooltip</em>. Ao usar um PC, a <em>tooltip </em>é exibida ao passar o mouse sobre o gráfico.</p><pre><code class="language-javascript">xAxis_crosshair_enabled: true,</code></pre><p>Você deve estar se perguntando: por que todos esses sublinhados nos nomes das propriedades? Esse não é o nome real da propriedade. É uma forma abreviada de escrever:</p><pre><code class="language-javascript">xAxis: {crosshair: {enabled: true}},</code></pre><p>Você pode achar mais conveniente especificar uma configuração com sublinhados e o JSCharting entenderá o que você quer dizer.</p><p>O texto padrão da <em>tooltip </em>é claro, mas vamos personalizá-lo um pouco para torná-lo nosso.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-60.png" class="kg-image" alt="image-60" width="308" height="203" loading="lazy"><figcaption>Tooltip combinada padrão</figcaption></figure><p>Como <em>tooltip</em> mostra informações sobre cada ponto, o texto é definido nas opções de ponto. A propriedade <code>defaultPoint</code> define as opções de ponto que todos os pontos herdarão automaticamente.</p><pre><code class="language-javascript">defaultPoint_tooltip: '%seriesName &lt;b&gt;%yValue&lt;/b&gt; years',</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-61.png" class="kg-image" alt="image-61" width="342" height="202" loading="lazy"><figcaption>Tooltip personalizada combinada</figcaption></figure><p>Para obter mais informações sobre esse recurso, consulte o <a href="https://jscharting.com/tutorials/js-chart-interactivity/crosshair-combined-tooltip/">tutorial sobre mouse de mira (ponto focal) e <em>tooltip</em></a><em> </em>(texto em inglês).</p><p>Quando você aplicar todas essas opções, seu código será semelhante ao trecho a seguir. Substitua toda a função <code>renderChart()</code> por este código:</p><pre><code class="language-javascript">function renderChart(series){
	JSC.Chart('chartDiv', {
		title_label_text: 'Life Expectancy in the United States',
		annotations: [{
			label_text: 'Source: National Center for Health Statistics',
			position: 'bottom left'
		}],
        legend_visible: false,
		defaultSeries_lastPoint_label_text: '&lt;b&gt;%seriesName&lt;/b&gt;',
		defaultPoint_tooltip: '%seriesName &lt;b&gt;%yValue&lt;/b&gt; years',
		xAxis_crosshair_enabled: true,
		series: series
	});
}
</code></pre><p>Atualize a janela do navegador mais uma vez.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart-tooltips.png" class="kg-image" alt="csv-line-chart-tooltips" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/csv-line-chart-tooltips.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/csv-line-chart-tooltips.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/csv-line-chart-tooltips.png 1282w" sizes="(min-width: 720px) 720px" width="1282" height="536" loading="lazy"><figcaption>Gráfico de linhas com mouse de mira e tooltip personalizada combinados</figcaption></figure><p>Você conseguiu!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/congratulations.gif" class="kg-image" alt="congratulations" width="444" height="250" loading="lazy"><figcaption>Fonte: giphy.com</figcaption></figure><p>Primeiro, você buscou dados CSV usando JavaScript nativo. Em seguida, você os converteu no formato JSON e filtrou os dados em duas séries. Com essas séries, você criou um belo gráfico de linhas interativo usando o JSCharting e o configurou para ter uma aparência profissional.</p><p>Você pode personalizar e ajustar ainda mais os gráficos para atender às suas necessidades específicas. Visite a seção de <a href="https://jscharting.com/tutorials/">tutoriais</a> para saber mais sobre um tópico específico ou encontre gráficos semelhantes ao que deseja criar na <a href="https://jscharting.com/examples/chart-types/">galeria de exemplos</a> e copie-os para continuar sua jornada de visualização de dados.</p><p>Se tiver problemas ao trabalhar com o JSCharting, sinta-se à vontade para entrar em <a href="https://jscharting.com/support.htm">contato</a> com a equipe de suporte. Eles terão prazer em orientá-lo ou ajudar a resolver qualquer problema que você possa encontrar.</p><p><strong><strong><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step4-b.zip">step4-b.zip</a></strong></strong></strong></strong></p><h2 id="desafio-adicional"><strong>Desafio adicional</strong></h2><p>Não usamos todos os dados disponíveis nesse arquivo CSV. Vamos fazer experiências com ele para nos divertirmos e praticarmos.</p><p>Crie este gráfico usando o que você aprendeu:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/bonus-trend-line-chart.png" class="kg-image" alt="bonus-trend-line-chart" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/bonus-trend-line-chart.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/bonus-trend-line-chart.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/bonus-trend-line-chart.png 1278w" sizes="(min-width: 720px) 720px" width="1278" height="537" loading="lazy"><figcaption>Desafio: replicar este gráfico por conta própria</figcaption></figure><p>Este arquivo zip contém a resposta:</p><p><strong><strong><a href="https://github.com/arthurPuszynski/first-chart-article/raw/master/zips/step5-bonus.zip">step5-bonus.zip</a></strong></strong></p><p>Você consegue pensar em outros gráficos que pode fazer com esses dados? Continue experimentando e aproveite cada minuto!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de promises em JavaScript – como concluir ou rejeitar promises em JS ]]>
                </title>
                <description>
                    <![CDATA[ Promises são blocos de construção importantes para operações assíncronas em JavaScript. Você pode pensar que as promises não são tão fáceis de entender, aprender e usar – acredite, você não está sozinho! As promises (em português, promessas) são um desafio para muitos desenvolvedores da Web, mesmo depois de passar anos ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tutorial-de-promises-em-javascript-como-concluir-ou-rejeitar-promises-em-js/</link>
                <guid isPermaLink="false">6514e8a386ff8703fbd88226</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Filipe Virgínio Vital Torres Barbosa ]]>
                </dc:creator>
                <pubDate>Mon, 13 May 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">JavaScript Promise Tutorial – How to Resolve or Reject Promises in JS</a>
      </p><p><code>Promises</code> são blocos de construção importantes para operações assíncronas em JavaScript. Você pode pensar que as <em>promises</em> não são tão fáceis de entender, aprender e usar – acredite, você não está sozinho!</p><p>As <em>promises</em> (em português, promessas) são um desafio para muitos desenvolvedores da Web, mesmo depois de passar anos trabalhando com elas.</p><p>Neste artigo, quero tentar mudar essa percepção ao compartilhar o que aprendi sobre <em>promises</em> em JavaScript nos últimos anos. Espero que seja útil para você.</p><h1 id="o-que-uma-promise-no-javascript"><strong>O que é uma <em>promise</em> no JavaScript?</strong></h1><p>Uma <code>Promise</code> é um objeto especial no JavaScript. Ela produz um valor após uma operação <code>assícrona</code> (também conhecida como <em>async</em>) ser concluída com êxito, ou um erro se ela não for concluída com sucesso, seja porque excedeu o limite de tempo, por erro de rede etc.</p><p>As conclusões de chamadas bem-sucedidas são indicadas pela chamada da função <code>resolve</code> e os erros são indicados pela chamada da função <code>reject</code>.</p><p>Você pode criar uma <em>promise </em>usando o construtor de <em>promises</em> da seguinte forma:</p><pre><code class="language-js">let promise = new Promise(function(resolve, reject) {    
    // Faz uma chamada assíncrona e conclui ou rejeita essa chamada
});</code></pre><p>Na maioria dos casos, uma <em>promise </em>pode ser usada para uma operação assíncrona. Entretanto, tecnicamente, você pode concluir/rejeitar operações síncronas e assíncronas.</p><h1 id="espere-a-n-o-temos-fun-es-de-callback-para-opera-es-ass-ncronas">Espere aí, não temos funções de<strong> <code>callback</code> </strong>para operações assíncronas<strong>?</strong></h1><p>Sim, está correto. Temos funções de <code>callback</code> no JavaScript. Porém, uma função de <em>callback </em>não é algo especial no JavaScript. É uma função normal que produz resultados após a conclusão de uma chamada <code>assíncrona</code> (com sucesso/erro).</p><p>A palavra "assíncrona" significa que algo acontece no futuro, não agora. Normalmente, <em>callbacks</em> são usadas apenas para fazer coisas como chamadas de rede ou fazer <em>upload</em>/<em>download </em>de coisas, se comunicar com bancos de dados e assim por diante.</p><p>Embora <code>callbacks</code> sejam úteis, elas também têm uma grande desvantagem. Às vezes, podemos ter uma <em>callback</em> dentro de outra <em>callback</em> que está em outra <em>callback</em> e assim por diante. Sério! Vamos entender esse "inferno de callbacks" (do inglês, <em>callback hell</em>) com um exemplo.</p><h2 id="como-evitar-o-inferno-de-callbacks-exemplo-do-pizzahub"><strong>Como evitar o inferno de callbacks – exemplo do PizzaHub</strong></h2><p>Vamos pedir uma pizza Marguerita vegana 🍕 do PizzaHub. Quando fazemos o pedido, o PizzaHub detecta automaticamente nossa localização, encontra uma pizzaria próxima e verifica se a pizza que estamos pedindo está disponível.</p><p>Se estiver disponível, ele detecta que tipo de bebida recebemos gratuitamente junto com a pizza e, por fim, faz o pedido.</p><p>Se o pedido for feito com sucesso, receberemos uma mensagem com uma confirmação.</p><p>Então, como podemos codificar isso usando funções de <em>callback</em>? Eu criei algo parecido com isso:</p><pre><code class="language-js">function pedirPizza(tipo, nome) {
    
    // Consulta a pizzahub por uma loja
    query(`/api/pizzahub/`, function(resultado, erro){
       if (!error) {
           let idLoja = resultado.idLoja;
           
           // Obtém a loja e consulta as pizzas
           query(`/api/pizzahub/pizza/${idLoja}`, function(resultado, erro){
               if (!erro) {
                   let pizzas = resultado.pizzas;
                   
                   // Verifica se minha pizza está disponível
                   let minhaPizza = pizzas.find((pizza) =&gt; {
                       return (pizza.tipo===tipo &amp;&amp; pizza.nome===nome);
                   });
                   
                   // Verifique se há bebidas gratuitas
                   query(`/api/pizzahub/bebidas/${minhaPizza.id}`, function(resultado, erro){
                       if (!erro) {
                           let bebida = resultado.id;
                           
                           // Prepara um pedido
                           query(`/api/pedido`, {'tipo': tipo, 'nome': nome, 'bebida': bebida}, function(resultado, erro){
                              if (!erro) {
                                  console.log(`Seu pedido de ${tipo} ${nome} com ${bebida} foi realizado`);
                              } else {
                                  console.log(`Infelizmente, não temos pizzas para você hoje!`);
                              }
                           });

                       }
                   })
               }
           });
       } 
    });
}

// Chama a função orderPizza
pedirPizza('vegetariana', 'marguerita');</code></pre><p>Vamos dar uma olhada na função <code>pedirPizza</code> no código acima.</p><p>Ela chama uma API para obter o ID da pizzaria mais próxima. Depois disso, obtém a lista de pizzas disponíveis nesse restaurante. Então, ela verifica se a pizza que estamos pedindo foi encontrada e faz outra chamada à API para encontrar as bebidas para essa pizza. Por fim, a API de pedidos faz o pedido.</p><p>Aqui usamos uma <em>callback </em>para cada uma das chamadas de API. Isso nos leva a usar outra <em>callback </em>dentro da anterior, e assim por diante.</p><p>Isso significa que entramos em algo que chamamos (de forma muito expressiva) de <code>Inferno de Callbacks</code>. Ninguém quer isso, certo? Isso também forma uma pirâmide de código que não é apenas confusa, mas também propensa a erros.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/callback-hell.png" class="kg-image" alt="callback-hell" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/callback-hell.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/callback-hell.png 900w" width="900" height="500" loading="lazy"><figcaption>Demonstração do inferno das callbacks e a pirâmide gerada</figcaption></figure><p>Há algumas maneiras de sair do (ou não entrar no) <code>inferno de callbacks</code>. A mais comum é usar uma <code>Promise</code> ou função <code>async</code>. No entanto, para entender bem as funções <code>async</code>, primeiro é preciso ter uma boa compreensão das <code>Promises</code>.</p><p>Portanto, vamos começar e nos aprofundar nas <em>promises</em>.</p><h1 id="entendendo-os-estados-das-promises">Entendendo os estados das<strong> <em>promises</em></strong></h1><p>Apenas para revisar, uma promise pode ser criada com a sintaxe de construtor, dessa maneira:</p><pre><code class="language-js">let promise = new Promise(function(resolve, reject) {
  // Código a ser executado
});</code></pre><p>A função construtora recebe uma função como argumento. Essa função é chamada de <code>função executora</code>.</p><pre><code class="language-js">// Função executora passada como um argumento 
// para o construtor da Promise
function(resolve, reject) {
    // Sua lógica entra aqui...
}</code></pre><p>A função executora recebe dois argumentos: <code>resolve</code> e <code>reject</code>. Essas são as funções de callback fornecidas pela linguagem JavaScript. Sua lógica está dentro da função executora, que é executada automaticamente quando uma <code>new Promise</code> é criada.</p><p>Para que a <em>promise </em>seja eficaz, a função executora deve chamar uma das funções de <em>callback</em>, <code>resolve</code> ou <code>reject</code>. Aprenderemos mais sobre isso em detalhes daqui a pouco.</p><p>O construtor <code>new Promise()</code> retorna um objeto <code>promise</code>. Como a função executora precisa lidar com operações assíncronas, o objeto <em>promise </em>retornado deve ser capaz de informar quando a execução foi iniciada, concluída (<em>resolved</em>) ou retornada com erro (<em>rejected</em>).</p><p>Um objeto <code>promise</code> tem as seguintes propriedades internas:</p><ol><li><code>state</code> – essa propriedade pode ter os seguintes valores:</li></ol><ul><li><code>pending</code> – inicialmente, quando a função executora inicia a execução.</li><li><code>fulfilled</code> – quando a promise é concluída.</li><li><code>rejected</code> – quando a promise é rejeitada.</li></ul><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/states_1.png" class="kg-image" alt="states_1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/states_1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/states_1.png 900w" width="900" height="500" loading="lazy"><figcaption>Estados da <em>promise</em></figcaption></figure><p>2. &nbsp;<code>result</code> – essa propriedade pode ter os seguintes valores:</p><ul><li><code>undefined</code> – inicialmente, quando o valor do <code>state</code> é <code>pending</code>.</li><li><code>value</code> – quando <code>resolve(value)</code> é chamada.</li><li><code>error</code> – quando &nbsp;<code>reject(error)</code> é chamada.</li></ul><p>Essas propriedades internas são inacessíveis ao código, mas podem ser inspecionadas. Isso significa que poderemos inspecionar os valores das propriedades <code>state</code> e <code>result</code> usando a ferramenta de depuração, mas não poderemos acessá-las diretamente usando o programa.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/promise_state_inspect.png" class="kg-image" alt="promise_state_inspect" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/promise_state_inspect.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/promise_state_inspect.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/promise_state_inspect.png 1076w" width="1076" height="595" loading="lazy"><figcaption>É possível inspecionar as propriedades internas de uma <em>promise</em></figcaption></figure><p>O estado de uma <em>promise </em>pode ser <code>pending</code> (pendente), <code>fulfilled</code> (cumprida) ou <code>rejected</code> (rejeitada). Uma <em>promise </em>que é resolvida ou rejeitada é chamada de <code>settled</code> (liquidada).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/states_2.png" class="kg-image" alt="states_2" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/states_2.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/states_2.png 900w" width="900" height="500" loading="lazy"><figcaption>Uma <em>promise </em>liquidada é cumprida ou rejeitada</figcaption></figure><h3 id="como-as-promises-s-o-conclu-das-e-rejeitadas"><strong>Como as <em>promises </em>são concluídas e rejeitadas</strong></h3><p>Aqui temos um exemplo de uma <em>promise </em>que será concluída imediatamente (estado <code>fulfilled</code>) com o valor <code>Estou pronto</code>.</p><pre><code class="language-js">let promise = new Promise(function(resolve, reject) {
    resolve("Estou pronto");
});</code></pre><p>A <em>promise </em>abaixo será rejeitada (estado <code>rejected</code>) com a mensagem de erro <code>Algo não está correto!</code>.</p><pre><code class="language-js">let promise = new Promise(function(resolve, reject) {
    reject(new Error('Algo não está correto!'));
});</code></pre><p>Um ponto importante a observar:</p><p>Uma função executora de <em>promises </em>deve chamar apenas uma função <code>resolve</code> ou uma função <code>reject</code>. Uma vez que um estado seja alterado (<em>pending</em> =&gt; <em>fulfilled</em> ou <em>pending</em> =&gt; <em>rejected</em>), acabou. Qualquer outra chamada para <code>resolve</code> ou para <code>reject</code> será ignorada.</p><pre><code class="language-js">let promise = new Promise(function(resolve, reject) {
  resolve("Com certeza serei resolvido!");

  reject(new Error('Isso será ignorado?')); // ignorado
  resolve("Ignorado?"); // ignorado
});</code></pre><p>No exemplo acima, apenas o primeiro a ser resolvido será chamado e os demais serão ignorados.</p><h1 id="como-lidar-com-uma-promise-depois-de-cri-la">Como lidar com uma promise depois de criá-la</h1><p>Uma <code>Promise</code> usa uma função executora para concluir uma tarefa (principalmente de maneira assíncrona). Uma função consumidora (que usa um resultado da <em>promise</em>) deve ser notificada quando a função executora concluir (com sucesso) ou rejeitar (com erro).</p><p>Os métodos, <code>.then()</code>, <code>.catch()</code> e <code>.finally()</code>, ajudam a criar o vínculo entre a função executora e as funções consumidoras para que possam estar em sincronia quando uma <em>promise </em>for <code>concluída (resolve)</code> ou <code>rejeitada (reject)</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/consumer_executor.png" class="kg-image" alt="consumer_executor" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/consumer_executor.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/consumer_executor.png 900w" width="900" height="500" loading="lazy"><figcaption>Funções executora e consumidora</figcaption></figure><h2 id="como-usar-o-m-todo-then-da-promise"><strong>Como usar o método <code>.then()</code> da <em>promise</em></strong></h2><p>O método <code>.then()</code> deve ser chamado no objeto <em>promise </em>para lidar com um resultado (resolve) ou um erro (reject).</p><p>Aceita duas funções como parâmetros. Normalmente, o método <code>.then()</code> deve ser chamado a partir da função consumidora em que você gostaria de saber o resultado da execução de uma <em>promise</em>.</p><pre><code class="language-js">promise.then(
  (result) =&gt; { 
     console.log(result);
  },
  (error) =&gt; { 
     console.log(error);
  }
);</code></pre><p>Se estiver interessado apenas em resultados bem-sucedidos, pode passar apenas um argumento, desta maneira:</p><pre><code class="language-js">promise.then(
  (result) =&gt; { 
      console.log(result);
  }
);</code></pre><p>Se você estiver interessado apenas no erro, poderá passar <code>null</code> para o primeiro argumento, assim:</p><pre><code class="language-js">promise.then(
  null,
  (error) =&gt; { 
      console.log(error)
  }
);</code></pre><p>No entanto, pode tratar melhor os erros usando o método <code>.catch()</code>, que veremos em um minuto.</p><p>Vamos dar uma olhada em alguns exemplos de tratamento de resultados e erros usando os métodos <code>.then</code> e <code>.catch</code> . Tornaremos esse aprendizado um pouco mais divertido com algumas requisições assíncronas reais. Usaremos a PokeAPI para obter informações sobre Pokémons e concluí-las/rejeitá-las usando <em>promises</em>.</p><p>Primeiro, vamos criar uma função genérica que aceita um URL da PokeAPI como argumento e retorna uma <em>promise</em>. Se a chamada à API for bem-sucedida, uma <em>promise </em>concluída será retornada. Uma <em>promise </em>rejeitada é retornada para qualquer tipo de erro.</p><p>A partir de agora, usaremos essa função em vários exemplos para obter uma <em>promise </em>e trabalhar com ela.</p><figure class="kg-card kg-code-card"><pre><code class="language-js">function getPromise(URL) {
  let promise = new Promise(function (resolve, reject) {
    let req = new XMLHttpRequest();
    req.open("GET", URL);
    req.onload = function () {
      if (req.status == 200) {
        resolve(req.response);
      } else {
        reject("Ocorreu um erro!");
      }
    };
    req.send();
  });
  return promise;
}</code></pre><figcaption>Método utilitário para obter uma <em>promise</em></figcaption></figure><p>Exemplo 1: obter informações de 50 Pokémons:</p><pre><code class="language-js">const ALL_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon?limit=50';

// Já discutimos essa função!
let promise = getPromise(ALL_POKEMONS_URL);

const consumer = () =&gt; {
    promise.then(
        (result) =&gt; {
            console.log({result}); // Exibe o retorno de 50 Pokémons no console do navegador
        },
        (error) =&gt; {
            // Como o URL é válido, isso não será chamado.
            console.log('Encontramos um erro!'); // Exibe um erro no console do navegador
    });
}

consumer();</code></pre><p>Exemplo 2: vamos tentar um URL inválido</p><pre><code class="language-js">const POKEMONS_BAD_URL = 'https://pokeapi.co/api/v2/pokemon-bad/';

// Isso será rejeitado porque o URL retorna erro 404
let promise = getPromise(POKEMONS_BAD_URL);

const consumer = () =&gt; {
    promise.then(
        (result) =&gt; {
            // A promise não foi concluída. Portanto, ela não será executada.
            console.log({result});
        },
        (error) =&gt; {
            // Uma promise rejeitada executará o seguinte
            console.log('We have encountered an Error!'); // Exibe um erro no console do navegador
        }
    );
}

consumer();</code></pre><h2 id="como-usar-o-m-todo-catch-da-promise"><strong>Como usar o método <code>.catch()</code> da <em>promise</em></strong></h2><p>Você pode usar esse método para lidar com erros (rejeições) das <em>promises</em>. A sintaxe de passar <code>null</code> como o primeiro argumento para <code>.then()</code> não é uma boa maneira de tratar erros. Portanto, temos o <code>.catch()</code> para fazer o mesmo trabalho com uma sintaxe simples:</p><pre><code class="language-js">// Isso será rejeitado porque o URL retorna 404
let promise = getPromise(POKEMONS_BAD_URL);

const consumer = () =&gt; {
    promise.catch(error =&gt; console.log(error));
}

consumer();</code></pre><p>Se lançarmos um erro usando <code>new Error("Algo está errado!")</code> em vez de chamar o <code>reject</code> da função executora e dos métodos da <em>promise</em>, ele ainda será tratado como uma rejeição. Isso significa que será capturado pelo método <code>.catch</code>.</p><p>O mesmo se aplica a todas as exceções <em>síncronas</em> que ocorrem no executor da <em>promise </em>e nas funções.</p><p>Aqui está um exemplo onde será tratado como uma rejeição e o método <code>.catch</code> será chamado:</p><pre><code class="language-js">new Promise((resolve, reject) =&gt; {
  throw new Error("Algo está errado!");// Sem chamada rejeitada
}).catch((error) =&gt; console.log(error)); </code></pre><h2 id="como-usar-o-m-todo-finally-da-promise"><strong>Como usar o método <code>.finally()</code> da <em>promise</em></strong></h2><p>O método <code>.finally()</code> realiza tarefas de limpeza como parar um carregamento, fechar uma conexão ativa e assim por diante. O método <code>finally()</code> será chamado independentemente da <em>promise </em>retornar um resultado (<code>resolve</code>) ou um erro (<code>reject</code>). Ele passa o resultado ou o erro para o próximo método, que pode chamar os métodos .then() ou .catch() novamente.</p><p>Aqui temos um exemplo que ajudará você a entender os três métodos juntos:</p><pre><code class="language-js">let loading = true;
loading &amp;&amp; console.log('Carregando...');

// Obtendo a Promise
promise = getPromise(ALL_POKEMONS_URL);

promise.finally(() =&gt; {
    loading = false;
    console.log(`Promessa resolvida e o carregamento é ${loading}`);
}).then((result) =&gt; {
    console.log({result});
}).catch((error) =&gt; {
    console.log(error)
});</code></pre><p>Explicando em detalhes:</p><ul><li>O método <code>.finally()</code> torna o carregamento <code>false</code>.</li><li>Se a <em>promise</em> retornar um resultado (<code>resolve</code>), o método <code>.then()</code> será chamado. Se a <em>promise</em> retornar um erro (<code>reject</code>), o método <code>.catch()</code> será chamado. O <code>.finally()</code> será chamado independentemente do resolve ou do reject.</li></ul><h1 id="o-que-encadeamento-de-promises"><strong>O que é encadeamento de <em>promises</em>?</strong></h1><p>A chamada &nbsp;<code>promise.then()</code> sempre retorna uma <em>promise</em>. Essa <em>promise </em>terá o <code>state</code> como <code>pending</code> e <code>result</code> como <code>undefined</code>. Ela nos permite chamar o próximo método <code>.then</code> em uma nova <em>promise</em>.</p><p>Quando o primeiro método <code>.then</code> retornar um valor, o próximo método <code>.then</code> pode recebê-lo. O segundo pode passar para o terceiro <code>.then()</code> e assim por diante. Isto forma uma cadeia de métodos <code>.then</code> para transmitir as <em>promises</em>. Esse fenômeno é chamado de <code>Cadeia de Promises</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-105.png" class="kg-image" alt="image-105" width="480" height="566" loading="lazy"><figcaption>Cadeia de <em>promises</em></figcaption></figure><p>Aqui está um exemplo:</p><pre><code class="language-js">let promise = getPromise(ALL_POKEMONS_URL);

promise.then(result =&gt; {
    let onePokemon = JSON.parse(result).results[0].url;
    return onePokemon;
}).then(onePokemonURL =&gt; {
    console.log(onePokemonURL);
}).catch(error =&gt; {
    console.log('In the catch', error);
});</code></pre><p>Aqui, primeiro obtemos uma <em>promise </em>resolvida e, em seguida, extraímos o URL para chegar ao primeiro Pokémon. Em seguida, retornamos esse valor e ele será passado como uma <em>promise </em>para a próxima função .then(). Daí o resultado,</p><pre><code class="language-shell">https://pokeapi.co/api/v2/pokemon/1/</code></pre><p>O método <code>.then</code> pode retornar tanto:</p><ul><li>Um valor (já vimos isso)</li><li>Uma nova <em>promise</em>.</li></ul><p>Também pode lançar um erro.</p><p>Aqui está um exemplo em que criamos uma cadeia de <em>promises</em> com os métodos <code>.then</code> que retornam resultados e uma nova <em>promise</em>:</p><pre><code class="language-js">// Promise Chain with multiple then and catch
let promise = getPromise(ALL_POKEMONS_URL);

promise.then(result =&gt; {
    let onePokemon = JSON.parse(result).results[0].url;
    return onePokemon;
}).then(onePokemonURL =&gt; {
    console.log(onePokemonURL);
    return getPromise(onePokemonURL);
}).then(pokemon =&gt; {
    console.log(JSON.parse(pokemon));
}).catch(error =&gt; {
    console.log('In the catch', error);
});</code></pre><p>Na primeira chamada de <code>.then</code>, extraímos o URL e o retornamos como um valor. Esse URL será passado para a segunda chamada <code>.then</code> na qual estamos retornando uma nova <em>promise </em>tendo esse URL como argumento.</p><p>Essa <em>promise </em>será resolvida e passada para a cadeia, onde obteremos as informações sobre o Pokémon. Aqui está o resultado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-159.png" class="kg-image" alt="image-159" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-159.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-159.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-159.png 1382w" sizes="(min-width: 1200px) 1200px" width="1382" height="655" loading="lazy"><figcaption>Resultado da chamada da cadeia de promises</figcaption></figure><p>Caso ocorra um erro ou a rejeição de uma <em>promise</em>, o método .catch da cadeia será chamado.</p><p>Um ponto a ser observado: chamar <code>.then</code> várias vezes não forma uma cadeia de <em>promises</em>. Você pode acabar fazendo algo assim apenas para introduzir um bug no código:</p><pre><code class="language-js">let promise = getPromise(ALL_POKEMONS_URL);

promise.then(result =&gt; {
    let onePokemon = JSON.parse(result).results[0].url;
    return onePokemon;
});
promise.then(onePokemonURL =&gt; {
    console.log(onePokemonURL);
    return getPromise(onePokemonURL);
});
promise.then(pokemon =&gt; {
    console.log(JSON.parse(pokemon));
});
</code></pre><p>Chamamos o método <code>.then</code> três vezes na mesma <em>promise</em>, mas não passamos a <em>promise</em> adiante. Isso é diferente da cadeia de <em>promises</em>. No exemplo acima, o resultado será um erro.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-160.png" class="kg-image" alt="image-160" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-160.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-160.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-160.png 1408w" sizes="(min-width: 1200px) 1200px" width="1408" height="105" loading="lazy"></figure><h1 id="como-lidar-com-v-rias-promises">Como lidar com várias <em>promises</em></h1><p>Além dos métodos (.then, .catch e .finally), há seis métodos estáticos disponíveis na API da <em>promise</em>. Os primeiros quatro métodos aceitam um <em>array</em> de <em>promises </em>e as executam em paralelo.</p><ol><li>Promise.all</li><li>Promise.any</li><li>Promise.allSettled</li><li>Promise.race</li><li>Promise.resolve</li><li>Promise.reject</li></ol><p>Vamos examinar cada uma delas.</p><h2 id="o-m-todo-promise-all-"><strong>O método Promise.all()</strong></h2><p><code>Promise.all([promises])</code> aceita uma coleção (por exemplo, um <em>array</em>) de <em>promises </em>como argumento e as executa em paralelo.</p><p>Esse método aguarda a resolução de todas as <em>promises </em>e retorna o array de resultados das <em>promises</em>. Se alguma das <em>promises </em>for rejeitada ou falhar devido a um erro, todos os outros resultados das <em>promises</em> serão ignorados.</p><p>Vamos criar três <em>promises</em> para obter informações sobre três Pokémons.</p><pre><code class="language-js">const BULBASAUR_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/bulbasaur';
const RATICATE_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/raticate';
const KAKUNA_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/kakuna';


let promise_1 = getPromise(BULBASAUR_POKEMONS_URL);
let promise_2 = getPromise(RATICATE_POKEMONS_URL);
let promise_3 = getPromise(KAKUNA_POKEMONS_URL);</code></pre><p>Use o método Promise.all() passando um <em>array</em> de <em>promises</em>.</p><pre><code class="language-js">Promise.all([promise_1, promise_2, promise_3]).then(result =&gt; {
    console.log({result});
}).catch(error =&gt; {
    console.log('An Error Occurred');
});</code></pre><p>Saída:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-161.png" class="kg-image" alt="image-161" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-161.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-161.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-161.png 1067w" width="1067" height="165" loading="lazy"></figure><p>Como você pode ver, o resultado de todas as <em>promises</em> é retornado. O tempo para executar todas as <em>promises</em> é igual ao tempo máximo que a <em>promise</em> leva para ser executada.</p><h2 id="o-m-todo-promise-any-"><strong>O método Promise.any()</strong></h2><p><code>Promise.any([promises])</code> – semelhante ao método <code>all()</code>, <code>.any()</code> também aceita um <em>array</em> de <em>promises </em>para executá-las em paralelo. Esse método não espera que todas as <em>promises </em>sejam resolvidas. Ele finaliza quando qualquer uma das promises é resolvida.</p><pre><code class="language-javascript"> Promise.any([promise_1, promise_2, promise_3]).then(result =&gt; {
     console.log(JSON.parse(result));
 }).catch(error =&gt; {
     console.log('An Error Occurred');
 });</code></pre><p>A saída seria o resultado de qualquer uma das <em>promises </em>resolvidas:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-162.png" class="kg-image" alt="image-162" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-162.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-162.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-162.png 1373w" sizes="(min-width: 1200px) 1200px" width="1373" height="61" loading="lazy"></figure><h2 id="o-m-todo-promise-allsettled-"><strong>O método Promise.allSettled()</strong></h2><p><code>promise.allSettled([promises])</code> – esse método aguarda que todas as <em>promises </em>sejam resolvidas (resolve/reject) e retorna seus resultados como um <em>array</em> de objetos. Os resultados conterão um estado (fulfilled/rejected) e um valor, se for <em>fulfilled</em>. Em caso de status <em>rejected</em>, ele retornará um motivo para o erro.</p><p>Aqui está um exemplo de todas as <em>promessas</em> cumpridas (<em>fulfilled</em>):</p><pre><code class="language-js">Promise.allSettled([promise_1, promise_2, promise_3]).then(result =&gt; {
    console.log({result});
}).catch(error =&gt; {
    console.log('There is an Error!');
});</code></pre><p>Saída:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-163.png" class="kg-image" alt="image-163" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-163.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-163.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-163.png 1600w" sizes="(min-width: 1200px) 1200px" width="1600" height="213" loading="lazy"></figure><p>Se alguma das <em>promises</em> for rejeitada, por exemplo, a promise_1,</p><pre><code class="language-javascript">let promise_1 = getPromise(POKEMONS_BAD_URL);</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-164.png" class="kg-image" alt="image-164" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-164.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-164.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-164.png 1585w" sizes="(min-width: 1200px) 1200px" width="1585" height="211" loading="lazy"></figure><h2 id="o-m-todo-promise-race-"><strong>O método Promise.race()</strong></h2><p><code>Promise.race([promises])</code> – Aguarda a primeira <em>promise</em> (a mais rápida) ser concluída e retorna o respectivo resultado/erro.</p><pre><code class="language-js">Promise.race([promise_1, promise_2, promise_3]).then(result =&gt; {
    console.log(JSON.parse(result));
}).catch(error =&gt; {
    console.log('An Error Occured');
});</code></pre><p>Retorna a <em>promise </em>que foi resolvida mais rapidamente:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-165.png" class="kg-image" alt="image-165" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/image-165.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/image-165.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/image-165.png 1282w" sizes="(min-width: 1200px) 1200px" width="1282" height="40" loading="lazy"></figure><h2 id="o-m-todo-promise-resolve-reject"><strong>O método Promise.resolve/reject</strong></h2><p><code>Promise.resolve(value)</code> – Ele resolve uma <em>promise </em>com o valor passado. É o mesmo que o seguinte código:</p><pre><code class="language-js">let promise = new Promise(resolve =&gt; resolve(value));</code></pre><p><code>Promise.reject(error)</code> – Rejeita uma <em>promise </em>com o erro passado. É o mesmo que o seguinte código:</p><pre><code class="language-js">let promise = new Promise((resolve, reject) =&gt; reject(error));</code></pre><h1 id="podemos-reescrever-o-exemplo-da-pizzahub-com-promises">Podemos reescrever o exemplo da PizzaHub com <em>promises</em><strong>?</strong></h1><p>Claro, vamos fazer isso. Vamos supor que o método <code>query</code> retornará uma <em>promise</em>. Aqui está um exemplo de método query(). Na vida real, esse método pode se comunicar com um banco de dados e retornar resultados. Nesse caso, ele é bastante codificado, mas tem a mesma finalidade.</p><pre><code class="language-js">function query(endpoint) {
  if (endpoint === `/api/pizzahub/`) {
    return new Promise((resolve, reject) =&gt; {
      resolve({'idLoja': '123'});
    })
  } else if (endpoint.indexOf('/api/pizzahub/pizza/') &gt;=0) {
    return new Promise((resolve, reject) =&gt; {
      resolve({pizzas: [{'tipo': 'vegetariana', 'nome': 'marguerita', 'id': '123'}]});
    })
  } else if (endpoint.indexOf('/api/pizzahub/bebidas') &gt;=0) {
    return new Promise((resolve, reject) =&gt; {
      resolve({id: '10', 'tipo': 'vegetariana', 'nome': 'marguerita', 'bebida': 'coca'});
    })
  } else if (endpoint === `/api/order`) {
    return new Promise((resolve, reject) =&gt; {
      resolve({'tipo': 'vegetariana', 'nome': 'marguerita', 'bebida': 'coca'});
    })
  }
}</code></pre><p>Em seguida, a refatoração do nosso <code>callback hell</code>. Para isso, primeiro criaremos algumas funções lógicas:</p><pre><code class="language-js">// Retorna um id da loja
let getIdLoja = resultado =&gt; resultado.idLoja;

// Retorna uma promise com a lista de pizzas para uma loja
let getListaPizzas = idLoja =&gt; {
  const url = `/api/pizzahub/pizza/${idLoja}`;
  return query(url);
}

// Retorna uma promise com a pizza que combina com o pedido do cliente
let getMinhaPizza = (resultado, tipo, nome) =&gt; {
  let pizzas = resultado.pizzas;
  let minhaPizza = pizzas.find((pizza) =&gt; {
    return (pizza.tipo===tipo &amp;&amp; pizza.nome===nome);
  });
  const url = `/api/pizzahub/bebidas/${minhaPizza.id}`;
  return query(url);
}

// Retorna uma promise depois de fazer o pedido
let fazerPedido = resultado =&gt; {
  let bebida = resultado.id;
   return query(`/api/pedido`, {'tipo': resultado.tipo, 'nome': resultado.nome, 'bebida': resultado.bebida});
}

// Confirma o pedido
let confirmarPedido = resultado =&gt; {
    console.log(`Seu pedido de ${resultado.tipo} ${resultado.nome} com ${resultado.bebida} foi aceito!`);
}</code></pre><p>Use essas funções para criar as <em>promises </em>necessárias. É aqui que você deve comparar com o exemplo do <code>callback hell</code>. Este é bem mais legal e elegante.</p><pre><code class="language-js">function pedirPizza(tipo, nome) {
  query(`/api/pizzahub/`)
  .then(resultado =&gt; getIdLoja(resultado))
  .then(idLoja =&gt; getListaPizzas(idLoja))
  .then(resultado =&gt; getMinhaPizza(resultado, tipo, nome))
  .then(resultado =&gt; realizarPedido(resultado))
  .then(resultado =&gt; confirmarPedido(resultado))
  .catch(function(erro){
    console.log(`Infelimente, não temos pizzas para você hoje!`);
  })
}</code></pre><p>Por fim, chame o método pedirPizza() passando o tipo e o nome da pizza, da seguinte forma:</p><pre><code class="language-js">pedirPizza('vegetariana', 'marguerita');
</code></pre><h1 id="o-que-vem-a-seguir">O que vem a seguir<strong>?</strong></h1><p>Se você chegou até aqui e leu a maior parte das linhas acima, parabéns! Agora você já deve ter uma noção melhor das Promises do JavaScript. Todos os exemplos usados neste artigo estão neste <a href="https://github.com/atapas/js-promise-example">repositório do GitHub</a>.</p><p>Em seguida, você deve aprender sobre a função <code>async</code> no JavaScript, que simplifica ainda mais as coisas. A melhor maneira de aprender o conceito de <em>promises </em>do JavaScript é escrever pequenos exemplos e desenvolvê-los com base neles.</p><p>Independentemente do <em>framework </em>ou da biblioteca (Angular, React, Vue e assim por diante) que usarmos, as operações assíncronas são inevitáveis. Isso significa que precisamos entender as <em>promises </em>para que as coisas funcionem melhor.</p><p>Além disso, tenho certeza de que você achará o uso do método <code>fetch</code> muito mais fácil agora:</p><pre><code class="language-js">fetch('/api/user.json')
.then(function(response) {
    return response.json();
})
.then(function(json) {
    console.log(json); // {"name": "tapas", "blog": "freeCodeCamp"}
});</code></pre><ul><li>O método <code>fetch</code> retorna uma <em>promise</em>. Portanto, podemos chamar o método <code>.then</code> nele.</li><li>O restante é sobre a cadeia de <em>promises </em>que aprendemos neste artigo.</li></ul><h1 id="antes-de-terminarmos-">Antes de terminarmos<strong>...</strong></h1><p>Obrigado por ler até aqui! Vamos nos conectar. Você pode me mandar mensagens no Twitter<a href="https://twitter.com/tapasadhikary"> (@tapasadhikary)</a> com comentários.</p><p>Você também pode gostar destes artigos (em inglês):</p><ul><li><a href="https://blog.greenroots.info/javascript-undefined-and-null-lets-talk-about-it-one-last-time-ckh64kmz807v848s15kdkg3dd">JavaScript undefined and null: Let's talk about it one last time!</a></li><li><a href="https://blog.greenroots.info/javascript-equality-comparison-with-and-objectis-ckdpt2ryk01vel9s186ft8cwl">JavaScript: Equality comparison with ==, === and Object.is</a></li><li><a href="https://www.freecodecamp.org/news/javascript-this-keyword-binding-rules/">The JavaScript `this` Keyword + 5 Key Binding Rules Explained for JS Beginners</a></li><li><a href="https://www.freecodecamp.org/news/javascript-typeof-how-to-check-the-type-of-a-variable-or-object-in-js/">JavaScript TypeOf – How to Check the Type of a Variable or Object in JS</a></li></ul><p>Isso é tudo por enquanto. Voltaremos a nos ver em breve com meu próximo artigo. Até lá, cuide-se bem. 🙂</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Exemplo de codificação de URL em JavaScript – como usar encodeURIcomponent() e encodeURI() ]]>
                </title>
                <description>
                    <![CDATA[ Você pode até pensar que encodeURI e encodeURIComponent fazem a mesma coisa, ao menos ao olhar para seus nomes. Você também pode estar confuso sobre qual deles usar e quando usar. Neste artigo, tentarei desmistificar a diferença entre encodeURI e  encodeURIComponent. O que é um URI e qual a ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/exemplo-de-codificacao-de-url-em-javascript-como-usar-encodeuricomponent-e-encodeuri/</link>
                <guid isPermaLink="false">663ad3480e369603f905ea85</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Wed, 08 May 2024 01:42:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/05/richy-great-MAYEkmn7G6E-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-url-encode-example-how-to-use-encodeuricomponent-and-encodeuri/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">JavaScript URL Encode Example – How to Use encodeURIcomponent() and encodeURI()</a>
      </p><p>Você pode até pensar que <code>encodeURI</code> e <code>encodeURIComponent</code> fazem a mesma coisa, ao menos ao olhar para seus nomes. Você também pode estar confuso sobre qual deles usar e quando usar.</p><p>Neste artigo, tentarei desmistificar a diferença entre <code>encodeURI</code> e <code>encodeURIComponent</code>.</p><h3 id="o-que-um-uri-e-qual-a-sua-diferen-a-de-um-url"><strong>O que é um URI e qual a sua diferença de um URL?</strong></h3><p><strong><strong>URI</strong></strong> é a sigla para <em>Uniform Resource Identifier</em> (em português, identificador de recurso uniforme).<br><strong><strong>URL</strong></strong> é a sigla para <em>Uniform Resource Locator</em> (em português, localizador de recurso uniforme).</p><p>Qualquer coisa que identifique de modo único um recurso é seu URI: exemplos disso são o id, o nome ou o número no ISBN. Um URL especifica um recurso e como ele pode ser acessado (o protocolo). Todos os URLs são URIs, mas nem todo URI é um URL.</p><h3 id="por-que-precisamos-codific-los"><strong>Por que precisamos codificá-los?</strong></h3><p>URLs somente podem ter alguns caracteres do conjunto padrão de 128 caracteres ASCII. Caracteres reservados que não pertençam a esse conjunto devem ser codificados.</p><p>Isso significa que precisamos codificar esses caracteres ao passarmos um URL. Caracteres especiais, como <code>&amp;</code>, <code>espaço</code> e <code>!</code>, ao serem inseridos em um URL, necessitam de um "escape", ou podem causar situações imprevisíveis.</p><p>Casos de uso:</p><ol><li>O usuário enviou valores em um formulário que podem estar no formato de <em>string </em>e precisam ser passados, como campos de URL.</li><li>É preciso aceitar parâmetros de consulta em formato de <em>strings</em> para fazer solicitações do tipo GET.</li></ol><h3 id="qual-a-diferen-a-entre-encodeuri-e-encodeuricomponent"><strong>Qual é a diferença entre encodeURI e encodeURIComponent?</strong></h3><p><code>encodeURI</code> e <code>encodeURIComponent</code> são usados para codificar os identificadores de recurso uniformes (URIs) ao substituir determinados caracteres por uma, duas, três ou quatro sequências de escape que representem a codificação UTF-8 do caractere.</p><p><code>encodeURIComponent</code> deve ser usado para codificar um <strong>componente U<strong>RI</strong></strong> – uma <em>string </em>que se suponha que seja parte de um URL.</p><p><code>encodeURI</code> deve ser usado para codificar um <strong><strong>URI</strong></strong> ou um URL existente.</p><p><a href="https://stackoverflow.com/a/23842171">Aqui temos uma tabela bastante útil para ver a diferença na codificação dos caracteres</a></p><h3 id="quais-caracteres-s-o-codificados"><strong>Quais caracteres são codificados?</strong></h3><p><code>encodeURI()</code> não codificará: <code>~!@#$&amp;*()=:/,;?+'</code></p><p><code>encodeURIComponent()</code> não codificará: <code>~!*()'</code></p><p>Os caracteres <code>A-Z a-z 0-9 - _ . ! ~ * ' ( )</code> não recebem o "escape".</p><h3 id="exemplos"><strong>Exemplos</strong></h3><pre><code class="language-js">const url = 'https://www.twitter.com'

console.log(encodeURI(url))             //Resultado: https://www.twitter.com
console.log(encodeURIComponent(url))    //Resultado: https%3A%2F%2Fwww.twitter.com


const paramComponent = '?q=search'
console.log(encodeURIComponent(paramComponent)) //Resultado: "%3Fq%3Dsearch"
console.log(url + encodeURIComponent(paramComponent)) //Resultado: https://www.twitter.com%3Fq%3Dsearch

</code></pre><h3 id="quando-codificar"><strong>Quando codificar</strong></h3><ol><li>Ao aceitar uma entrada que possa ter espaços.</li></ol><pre><code class="language-js">encodeURI("http://www.mysite.com/a file with spaces.html") //Resultado: http://www.mysite.com/a%20file%20with%20spaces.html
</code></pre><p>2. Ao criar um URL a partir de parâmetros de consulta em formato de <em>string</em>.</p><pre><code class="language-js"> let param = encodeURIComponent('mango')
 let url = "http://mysite.com/?search=" + param + "&amp;length=99"; //Resultado: http://mysite.com/?search=mango&amp;length=99

</code></pre><p>3. Ao aceitar parâmetros de consulta que possam ter caracteres reservados.</p><pre><code class="language-js">   let params = encodeURIComponent('mango &amp; pineapple')
   let url = "http://mysite.com/?search=" + params; //Resultado: http://mysite.com/?search=mango%20%26%20pineapple

</code></pre><p><strong>Resumo</strong></p><p>Se você tiver um URL completo, use <code>encodeURI</code>. Se, no entanto, tiver apenas parte de um URL, use <code>encodeURIComponent</code>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Não verifique o código apenas – conserte-o com o Prettier ]]>
                </title>
                <description>
                    <![CDATA[ O uso de linting (verificação de código) facilita nossas vidas pois nos diz o que há de errado no código. Como podemos, no entanto, evitar a realização do trabalho que passamos para consertar o código? Anteriormente, já escrevi sobre linting [https://www.freecodecamp.org/news/what-is-linting-and-how-can-it-save-you-time/]  (texto em inglês), sobre o que ele é ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/nao-verifique-o-codigo-apenas-conserte-o-com-o-prettier/</link>
                <guid isPermaLink="false">662effad28986303fd725f63</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Mon, 29 Apr 2024 02:48:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/formatting-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/dont-just-lint-your-code-fix-it-with-prettier/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Don’t just lint your code - fix it with Prettier</a>
      </p><p>O uso de <em>linting</em> (verificação de código) facilita nossas vidas pois nos diz o que há de errado no código. Como podemos, no entanto, evitar a realização do trabalho que passamos para consertar o código?</p><p><a href="https://www.freecodecamp.org/news/what-is-linting-and-how-can-it-save-you-time/">Anteriormente, já escrevi sobre <em>linting</em></a> (texto em inglês), sobre o que ele é e sobre como ele facilita nossas vidas. No fim, eu cheguei a recomendar um modo de consertar o código automaticamente. Assim sendo, por que eu estou escrevendo este artigo?</p><h2 id="o-que-voc-quer-dizer-com-consertar-o-c-digo"><strong><strong>O que você quer dizer com consertar o código<strong>?</strong></strong></strong></h2><p>Antes de nos aprofundarmos no assunto, vamos tratar disso rapidamente. <em>Linters</em> são muito poderosos e fornecem um modo fácil de verificar o código para ver se há erros de sintaxe que podem levar a <em>bugs</em>. Eles também podem, simplesmente, ajudar a manter uma base de código limpa, saudável e consistente. Ao executarmos um <em>linter</em>, ele mostrará todos os problemas e permitirá que examinemos um por um, individualmente, para consertarmos os erros.</p><p>Podemos levar isso um nível adiante. Alguns <em>linters</em>, de fato, permitirão que você passe um argumento ao comando que executa o <em>linter</em> que ajudarão a consertar o erro "automagicamente". Isso quer dizer que você não precisa examinar o código manualmente e fazer os ajustes finos de espaços em branco e de pontos-e-vírgulas (tendo de adicionar um por um) por conta própria!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/ron-swanson-happy.gif" class="kg-image" alt="ron-swanson-happy" width="480" height="267" loading="lazy"><figcaption>Ron Swanson feliz</figcaption></figure><h2 id="o-que-mais-eu-posso-fazer-para-consertar-tudo"><strong><strong>O que mais eu posso fazer para consertar tudo<strong>?</strong></strong></strong></h2><p>Se você já usou a opção de consertar, temos um bom ponto de partida. No entanto, há algumas ferramentas que foram desenvolvidas especificamente para lidar com esse problema para além de apenas sinalizá-lo no seu comando. Hoje, tratarei do Prettier.</p><h2 id="o-que-o-prettier"><strong><strong>O que é o<strong> Prettier?</strong></strong></strong></h2><p><a href="https://prettier.io/">Prettier</a> considera a si mesmo "um formatador de código com opinião formada". Ele recebe seu código como entrada e o retorna um uma formatação consistente, removendo qualquer estilo do código original e substituindo pelo seu. Ele, de fato, converte seu código em uma <a href="https://github.com/benjamn/recast">árvore sintática</a>, reescrevendo-o em seguida usando estilos e regras que você e o próprio Prettier fornecem por meio da configuração do seu ESLint e das regras padrão do Prettier.</p><p>Você pode usar o Prettier facilmente por conta própria apenas para formatar seu código. Isso já funciona bem. No entanto, se você combiná-lo com um processo de ESLint operando em conjunto, terá tanto um <em>linter </em>poderoso como um consertador de códigos de respeito. Mostrarei a você como fazer para que eles funcionem juntos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/voltron.gif" class="kg-image" alt="voltron" width="500" height="386" loading="lazy"><figcaption>Voltron</figcaption></figure><h2 id="no-es-b-sicas-do-prettier"><strong><strong>Noções básicas do <strong>Prettier</strong></strong></strong></h2><p>Para este passo a passo, vou assumir que você já tem o ESLint configurado e preparado para uma aplicação. Particularmente, vou começar de onde eu parei em meu passo a passo anterior, onde <a href="https://www.freecodecamp.org/news/what-is-linting-and-how-can-it-save-you-time/">instalamos o ESLint para uma aplicação do React</a> (texto em inglês).</p><p>Também é bom ressaltar que o Prettier nos diz já de início que ele é um formatador de código com opinião formada . Você deve esperar que ele formate seu código de maneira consistente, mas talvez de um modo diferente daquele que você configurou até agora. Não se assuste! Você pode ajustar essa configuração.</p><p>De onde estamos começando? Nós já:</p><ul><li>instalamos o <a href="https://github.com/eslint/eslint">ESLint</a></li><li>adicionamos o <a href="https://github.com/babel/babel-eslint">Babel</a> como nosso <em>parser </em>de código</li><li>adicionamos um <a href="https://github.com/yannickcr/eslint-plugin-react">plug-in</a> que inclui configurações do React</li></ul><p>Em seguida, vamos começar instalando alguns pacotes:</p><pre><code class="language-shell">yarn add prettier prettier-eslint prettier-eslint-cli -D</code></pre><p><em>Observação<em>: </em>o comando acima é semelhante ao do <em><code>npm</code>. </em>Se o seu projeto não usa o<em> <code>yarn</code>, </em>troque por<em> <code>npm</code> </em>onde for apropriado<em>.</em></em></p><p>Acima, instalamos:</p><ul><li><a href="https://github.com/prettier/prettier">prettier</a>: o pacote principal do Prettier e sua engine</li><li><a href="https://github.com/prettier/prettier-eslint">prettier-lint</a>: passa o resultado do Prettier para o ESLint para que ele o conserte usando sua configuração do ESLint</li><li><a href="https://github.com/prettier/prettier-eslint-cli">prettier-eslint-cli</a>: ajuda o Prettier e o ESLint a trabalharem juntos em diversos arquivos por todo o seu projeto</li></ul><p>É importante notar que estamos instalando tudo isso como dependências de desenvolvimento, pois não precisaremos delas depois disso.</p><h2 id="configurando-seu-novo-formatador"><strong><strong><strong>Configur</strong>ando seu novo formatador</strong></strong></h2><p>Agora que nossos pacotes estão instalados, podemos solicitar ao <code>yarn</code> que execute esse código para nós.</p><p>Anteriormente, definimos um script de <code>lint</code> para que tivesse esta aparência no <code>package.json</code>:</p><pre><code class="language-json">"scripts": {
  ...
  "lint": "eslint . --ext .js"
  ...
}</code></pre><p>Vamos deixar isso como está, mas faremos algo parecido e criaremos um script próximo a isso, chamado <code>format</code>, para nosso formatador, o Prettier:</p><pre><code class="language-json">"scripts": {
  ...
  "format": "prettier-eslint --eslint-config-path ./.eslintrc.js --write '**/*.js'",
  "lint": "eslint . --ext .js"
  ...
}</code></pre><p>O que está ocorrendo aqui? Estamos:</p><ul><li>Adicionando um novo script chamado <code>format</code>, que pode ser executado com <code>yarn format</code></li><li>utilizando o pacote <code>prettier-eslint-cli</code> para executar a formatação para nós</li><li>passando nossa configuração do ESLint, localizada ao lado do nosso <code>package.json</code>, na raiz do projeto (altere o caminho se estiver em um local diferente)</li><li>e, por fim, dizendo ao Prettier que reescreva todos os artigos que tenham <code>**/*.js</code> como correspondência, ou quaisquer arquivos de JS que sejam encontrados recursivamente em nosso projeto</li></ul><p>A beleza está no fato de que estamos passando nossa configuração do ESLint para o Prettier. Isso quer dizer que precisamos apenas manter uma configuração para ambas as ferramentas e que ainda podemos aproveitar do poder de verificação do ESLint, juntamente do poder formatador do Prettier.</p><h2 id="execute-seu-formatador-"><strong><strong>Execute seu formatador<strong>!</strong></strong></strong></h2><p>Agora que está tudo configurado, vamos executar! Faça isso com o seguinte comando:</p><pre><code>yarn format
</code></pre><p>Veremos que isso funciona imediatamente:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/prettier-command-line-success.png" class="kg-image" alt="prettier-command-line-success" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/prettier-command-line-success.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/prettier-command-line-success.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/prettier-command-line-success.png 1434w" sizes="(min-width: 720px) 720px" width="1434" height="176" loading="lazy"><figcaption>Rodando o Prettier com sucesso</figcaption></figure><h2 id="ei-meu-c-digo-parece-diferente-"><strong><strong>Ei<strong>, m</strong>eu código parece diferente<strong>!</strong></strong></strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/spongebob-pitchforks.gif" class="kg-image" alt="spongebob-pitchforks" width="480" height="360" loading="lazy"><figcaption>Multidão raivosa com tridentes</figcaption></figure><p>Como eu mencionei antes, o Prettier nos avisa de cara que ele é um formatador de código com opinião formada. Ele vem com suas próprias regras, algo como sua própria configuração do ESLint, o que fará com que ele percorra o código e faça essas alterações também.</p><p>Não abandone seu código! Em vez disso, você pode revisar as alterações e ver se, talvez, faça sentido mantê-las como estão (elas estarão bastante consistentes) ou você pode atualizar sua configuração do ESLint (<code>.eslintrc.js</code>) para sobrescrever as regras de que você não gosta. Essa também é uma boa maneira de, talvez, aprender algumas coisas novas pelas quais você pode não ter esperado enfrentar.</p><h2 id="onde-isso-nos-deixa-ent-o"><strong><strong>Onde isso nos deixa, então<strong>?</strong></strong></strong></h2><p>Se você acompanhou até aqui, agora temos dois comandos:</p><ul><li><code>lint</code>: verificará seu código por você e contará o que está errado</li><li><code>format</code>: tentará automaticamente consertar os problemas para você</li></ul><p>Ao usá-los na prática, o mais seguro é sempre executar <code>format</code> primeiro para deixar que ele tente consertar automaticamente tudo o que puder. Em seguida, imediatamente, execute o <code>lint</code> para epgar tudo aquilo que o Prettier não conseguiu consertar automaticamente.</p><h2 id="que-fa-o-depois-disso"><strong><strong>Que faço depois disso<strong>?</strong></strong></strong></h2><p>Agora que podemos formatar nosso código automaticamente, deveremos poder consertar nosso código automaticamente!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/fresh-off-the-boat-mind-blown.gif" class="kg-image" alt="fresh-off-the-boat-mind-blown" width="500" height="282" loading="lazy"><figcaption>O cérebro de Eddie, de Fresh Off the Boat, enlouquecido</figcaption></figure><p>Na próxima vez, daremos um passo a mais e configuraremos um <em>hook </em>do <code>git</code>, que permitirá que isso seja executado antes de você fazer o <em>commit</em>. Isso quer dizer que você não terá de se preocupar mais com esquecer de executar esses processos novamente!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/social-footer-card.jpeg" class="kg-image" alt="social-footer-card" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/social-footer-card.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/04/social-footer-card.jpeg 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/04/social-footer-card.jpeg 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/social-footer-card.jpeg 2000w" sizes="(min-width: 720px) 720px" width="2000" height="400" loading="lazy"></figure><ul><li><a href="https://twitter.com/colbyfayock">Siga o autor no Twitter</a></li><li><a href="https://youtube.com/colbyfayock">Inscreva-se no ️canal do YouTube do autor</a></li><li><a href="https://www.colbyfayock.com/newsletter/">✉️ Assine a newsletter do autor</a></li></ul><p><em>Publicado originalmente em<em> <a href="https://www.colbyfayock.com/2019/11/dont-just-lint-your-code-fix-it-with-prettier/">https://www.colbyfayock.com/2019/11/dont-just-lint-your-code-fix-it-with-prettier/</a></em></em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como a recursão funciona — explicado com fluxogramas e vídeo ]]>
                </title>
                <description>
                    <![CDATA[ (A ilustração da capa – bem como tudo neste artigo – é de Aditya Barghava) > "Para entender recursão, você primeiro precisa entender recursão." A recursão, ou recursividade, pode ser um assunto difícil de entender — especialmente para novos programadores. Em sua forma mais simples, uma função recursiva é uma ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-a-recursao-funciona-explicado-com-fluxogramas-e-video/</link>
                <guid isPermaLink="false">653de7bb41517403e4ea4f6a</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brainon Queiroz ]]>
                </dc:creator>
                <pubDate>Tue, 16 Apr 2024 02:05:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_FVSUmSQEEsagXaKa_ajtvA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-recursion-works-explained-with-flowcharts-and-a-video-de61f40cb7f9/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How Recursion Works — Explained with Flowcharts and a Video</a>
      </p><p><em>(A ilustração da capa – bem como tudo neste artigo – é de Aditya Barghava)</em></p><blockquote>"Para entender recursão, você primeiro precisa entender recursão."</blockquote><p>A recursão, ou recursividade, pode ser um assunto difícil de entender — especialmente para novos programadores. Em sua forma mais simples, uma função recursiva é uma função que invoca a si mesma. Deixe eu tentar explicar com um exemplo.</p><p>Imagine que você vai abrir a porta do seu quarto e encontra a porta trancada. Seu filho de três anos aparece e revela que ele trancou a porta e escondeu a chave em uma caixa ("Bem a cara dele", você pensa). Você está atrasado para o trabalho e precisa urgentemente entrar no quarto para pegar sua camisa.</p><p>Você abre a caixa apenas para encontrar... mais caixas! Caixas dentro de caixas. Você não sabe qual delas contêm a chave! Você precisa daquela camisa então decide pensar em um bom algoritmo para resolver este dilema.</p><p>Existem duas maneiras principais de se criar um algoritmo para este problema: iterativa e recursiva. Aqui estão ambas as maneiras explicadas com um fluxograma:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_QrQ5uFKIhK3jQSFYeRBIRg.png" class="kg-image" alt="1_QrQ5uFKIhK3jQSFYeRBIRg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_QrQ5uFKIhK3jQSFYeRBIRg.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_QrQ5uFKIhK3jQSFYeRBIRg.png 800w" sizes="(min-width: 720px) 720px" width="800" height="492" loading="lazy"></figure><p>Qual delas parece mais fácil?</p><p>A primeira maneira utiliza um laço <em>while</em>. Enquanto a pilha não estiver vazia, pegue uma caixa e verifique-a. Aqui está um pseudocódigo inspirado em Javascript que mostra o que está acontecendo (pseudocódigo é escrito como se fosse código, mas se assemelha a língua humana).</p><pre><code class="language-javascript">function procura_chave(caixa_principal) {
    let pilha = caixa_principal.fazer_pilha_para_procurar();
    while (pilha nao vazia) {
        caixa = pilha.pegar_caixa();
        for (item in caixa) {
            if (item.eh_uma_caixa()) {
                pilha.append(item)
            } else if (item.eh_uma_chave()) {
                console.log("achei a chave!")
            }
        }
    }}</code></pre><p>A segunda maneira utiliza a recursão. Lembre-se, recursão é quando uma função que invoca a si própria. Aqui está a segunda maneira em pseudocódigo.</p><pre><code class="language-javascript">function procura_chave(caixa) {
  for (item in caixa) {
    if (item.eh_uma_caixa()) {
      procura_chave(item);
    } else if (item.eh_uma_chave()) {
      console.log("achei a chave!")
    } 
  }
}</code></pre><p>Ambas as abordagens resultam na mesma coisa. O principal propósito de se utilizar recursão é que, depois que você entende o conceito, o código fica mais legível. Não existe nenhum benefício de desempenho ao se usar recursão. A solução iterativa, às vezes, pode ser até mais rápida, mas a simplicidade da recursão é preferida.</p><p>Além disso, como muitos algoritmos famosos utilizam recursão, é importante entender como funciona. Se recursão ainda não soa simples para você, não se preocupe: darei mais alguns exemplos.</p><h3 id="caso-base-e-caso-recursivo"><strong>Caso base e caso recursivo</strong></h3><p>Uma coisa que você deve tomar muito cuidado ao escrever uma função recursiva é com um laço infinito. Isso ocorre quando a função continua se invocando... e nunca para!</p><p>Por exemplo, se você quiser escrever uma função de contagem regressiva. Você poderia escrevê-la recursivamente em Javascript desse jeito:</p><pre><code class="language-javascript">// CUIDADO: esta função contém um laço infinito!
function contagemRegressiva(i) {
    console.log(i)
    contagemRegressiva(i - 1)
}

contagemRegressiva(5); // Essa é a chamada inicial da função.</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_LGjfggsIiQHbfJothG1hYw.png" class="kg-image" alt="1_LGjfggsIiQHbfJothG1hYw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_LGjfggsIiQHbfJothG1hYw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_LGjfggsIiQHbfJothG1hYw.png 800w" sizes="(min-width: 720px) 720px" width="800" height="321" loading="lazy"></figure><p>Essa função continuará se invocando pra sempre. Se você acidentalmente criou um código com um laço infinito, &nbsp;pode apertar "Ctrl+C" para encerrar seu script (ou, se estiver no CodePen, precisará adicionar "?turn_off_js=true" no fim da URL.)</p><p>Uma função recursiva sempre precisará de uma condição para dizer quando ela precisa parar de se invocar. Sempre existirão duas partes de uma função recursiva: O caso recursivo e o caso base. O caso recursivo é quando a função invoca a si mesma. O caso base é quando a função deverá parar de se invocar. Isso evitará os laços infinitos.</p><p>Aqui está a contagem regressiva novamente, desta vez com um caso base:</p><pre><code class="language-javascript">function contagemRegressiva(i) {
    console.log(i)  
    if (i &lt;= 1) {  // caso base
        return;
    } else {     // caso recursivo
        contagemRegressiva(i - 1);
    }
}

contagemRegressiva(5); // Essa é a chamada inicial da função.</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_rQ9Z3DmtGk1Bb6_Mx5W6rQ.png" class="kg-image" alt="1_rQ9Z3DmtGk1Bb6_Mx5W6rQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_rQ9Z3DmtGk1Bb6_Mx5W6rQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_rQ9Z3DmtGk1Bb6_Mx5W6rQ.png 800w" sizes="(min-width: 720px) 720px" width="800" height="463" loading="lazy"></figure><p>Pode não ser óbvio o que está acontecendo nessa função. Vou explicar o que acontece quando se executa a função <code>contagemRegressiva</code> passando "5" como argumento.</p><p>Começamos imprimindo o número 5 no console utilizando <code>console.log</code>. Como cinco não é menor ou igual a um, vamos para o bloco else. Lá, invocamos novamente a função <code>contagemRegressiva</code> com o número quatro (5-1=4).</p><p>Imprimimos o número 4. Novamente, <code>i</code> não é menor ou igual a um, então vamos para o bloco else e invocamos a função <code>contagemRegressiva</code> novamente com o argumento 3. Esse processo continua até <code>i</code><em><em> </em>ser igual a um</em>. Quando isso acontecer, imprimimos o número um &nbsp;e então <code>i</code><em><em> </em>será menor ou igual a um</em>. Finalmente chegamos à declaração de retorno, então encerramos o laço e saímos da função.</p><h3 id="call-stack">Call stack</h3><p>Funções recursivas utilizam algo chamado "<em>call stack</em>" (ou "pilha de chamadas", em português). Quando um programa invoca uma função, essa função vai para o topo dessa pilha. Essa estrutura é similar à uma pilha de livros. Você adiciona livros na pilha um de cada vez. Então quando você quer retirar um livro da pilha, você sempre tira primeiro o livro do topo.</p><p>Vou mostrar a pilha de chamadas em ação com a função <code>fatorial</code>. A expressão <code>fatorial(5)</code> é escrita como 5! e é definida assim: 5! = 5 * 4 * 3 * 2 * 1. Aqui está uma função recursiva para calcular o fatorial de um número.</p><pre><code class="language-javascript">function fatorial(x) {
    if (x == 1) {
        return 1;
    } else {
        return x * fatorial(x-1);
    }
}</code></pre><p>Agora, vamos ver o que acontece se você chamar <code>fatorial(3)</code>. A ilustração abaixo mostra como a pilha de chamada (<em>call stack</em>) funciona, linha por linha. A chamada mais ao topo da pilha mostra qual chamada de <code>fatorial</code> (no exemplo em inglês, <code>fact</code>) está sendo executada no momento.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_YRkMsMPRFAt8Y9BiC0QVDg.png" class="kg-image" alt="1_YRkMsMPRFAt8Y9BiC0QVDg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_YRkMsMPRFAt8Y9BiC0QVDg.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_YRkMsMPRFAt8Y9BiC0QVDg.png 800w" sizes="(min-width: 720px) 720px" width="800" height="1065" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_AWu17xnQ-lxVwpgVhEo_lA.png" class="kg-image" alt="1_AWu17xnQ-lxVwpgVhEo_lA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_AWu17xnQ-lxVwpgVhEo_lA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_AWu17xnQ-lxVwpgVhEo_lA.png 800w" sizes="(min-width: 720px) 720px" width="800" height="342" loading="lazy"><figcaption>Crédito da imagem: Aditya Bhargava</figcaption></figure><p>Note como cada chamada de <code>fatorial</code> tem sua própria cópia de <code>x</code>. Isso é muito importante para fazer com que a recursão funcione. Você não pode acessar a cópia de <code>x</code> de uma função diferente.</p><h3 id="j-encontrou-a-chave"><em><strong>Já encontrou a chave</strong><em><strong>?</strong></em></em></h3><p>Vamos voltar brevemente ao exemplo original sobre procurar a chave nas caixas aninhadas. Lembre-se, o primeiro método foi iterativo utilizando um laço <em>while</em>. Com aquele método, você primeiro alinha as caixas e depois procura em cada uma delas, assim você sempre sabe em quais caixas você ainda precisa procurar.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_qFezr1s9YpK6-GsMJqwhOA.png" class="kg-image" alt="1_qFezr1s9YpK6-GsMJqwhOA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_qFezr1s9YpK6-GsMJqwhOA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_qFezr1s9YpK6-GsMJqwhOA.png 800w" sizes="(min-width: 720px) 720px" width="800" height="602" loading="lazy"></figure><p>Essa abordagem, porém, não existe no método recursivo. Como seu algoritmo sabe em quais caixas você ainda precisa procurar? A "pilha de caixas" é salva na <em>stack</em>. Essa <em>stack </em>consiste em chamadas de funções "meio completas", cada uma com suas listas "meio completas" para serem verificadas. A <em>stack </em>gerencia toda essa pilha para você!</p><p>Graças à recursão, você pode finalmente encontrar a chave e pegar sua camisa!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_8Y0_goJ5oKvt1tzSX4d8Tw.png" class="kg-image" alt="1_8Y0_goJ5oKvt1tzSX4d8Tw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/04/1_8Y0_goJ5oKvt1tzSX4d8Tw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_8Y0_goJ5oKvt1tzSX4d8Tw.png 800w" sizes="(min-width: 720px) 720px" width="800" height="948" loading="lazy"></figure><p>Você também pode assistir esse vídeo (em inglês) de 5 minutos sobre recursão. Isso vai ajudar a reforçar esses conceitos de recursão.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/vPEJSJMg4jY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Recursion in software development" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h3 id="conclus-o">Conclusão</h3><p>Espero que este artigo tenha trazido mais clareza sobre recursão na programação. Este artigo é baseado em meu novo curso na Manning Publications chamado <a href="https://www.manning.com/livevideo/algorithms-in-motion?a_aid=algmotion&amp;a_bid=9022d293" rel="noopener">Algorithms in Motion</a> (Algoritmos em movimento). O curso (bem como este artigo) é baseado no incrível livro <a href="https://www.amazon.com.br/Entendendo-Algoritmos-ilustrado-programadores-curiosos-ebook/dp/B07B61HC3L/ref=sr_1_2?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=133K2BLHICWLZ&amp;dib=eyJ2IjoiMSJ9.Wv6UVv25BsUBwcrCqITDs-m0BkMNBl-LKfHg-sIuts4c49DpYxB0_DuUQQGQb3x0xf0NRhDsI9S2gZhX08_fVEf0SxSgh0k9HYYT0QzZIVtyuKYRJB8NziEokgXfelyPsx1u6WfPdPDvKbvd2sVB_NqbvQmdVmrmHXh0mSXkbwGsdyFmoWc3KNdOYlX6eNBqOWVORV8zAtQefhgB-f1c9RxUpYmtyGWCGdeDOxAiNIe3jzfl9KuxE8I8YupBE_odaOrTkq45LvUfNmNumUGs1naqBkGdrrccRcaax1eQMz0.ilAagk3S36f7vXESs77PBU3EE_3NwCIuhcAZoHbVjl8&amp;dib_tag=se&amp;keywords=algoritmos+de+grokking&amp;qid=1713165925&amp;sprefix=algoritmos+de+grokking%2Caps%2C246&amp;sr=8-2">Entendendo algoritmos</a>, de Aditya Bhargava. Foi ele quem desenhou todas as ilustrações deste artigo.</p><p>Se você aprende melhor lendo livros, <a href="https://www.amazon.com.br/Entendendo-Algoritmos-ilustrado-programadores-curiosos-ebook/dp/B07B61HC3L/ref=sr_1_2?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=133K2BLHICWLZ&amp;dib=eyJ2IjoiMSJ9.Wv6UVv25BsUBwcrCqITDs-m0BkMNBl-LKfHg-sIuts4c49DpYxB0_DuUQQGQb3x0xf0NRhDsI9S2gZhX08_fVEf0SxSgh0k9HYYT0QzZIVtyuKYRJB8NziEokgXfelyPsx1u6WfPdPDvKbvd2sVB_NqbvQmdVmrmHXh0mSXkbwGsdyFmoWc3KNdOYlX6eNBqOWVORV8zAtQefhgB-f1c9RxUpYmtyGWCGdeDOxAiNIe3jzfl9KuxE8I8YupBE_odaOrTkq45LvUfNmNumUGs1naqBkGdrrccRcaax1eQMz0.ilAagk3S36f7vXESs77PBU3EE_3NwCIuhcAZoHbVjl8&amp;dib_tag=se&amp;keywords=algoritmos+de+grokking&amp;qid=1713165925&amp;sprefix=algoritmos+de+grokking%2Caps%2C246&amp;sr=8-2">adquira o livro</a>! Se você aprende melhor assistindo vídeos, considere <a href="https://www.manning.com/livevideo/algorithms-in-motion?a_aid=algmotion&amp;a_bid=9022d293">adquirir meu curso</a> (em inglês).</p><blockquote>Tenha 39% de desconto no meu curso usando o código '<strong><strong>39carnes</strong></strong>'!</blockquote><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/04/1_a5UFtQIHwXy7SCQpI9GdVQ.png" class="kg-image" alt="1_a5UFtQIHwXy7SCQpI9GdVQ" width="260" height="326" loading="lazy"></figure><p>Por fim, para realmente entender recursão, leia este artigo de novo!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma aplicação em tempo real usando Socket.io, React, Node e MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ > Nota da tradução: o artigo a seguir foi escrito quando o React estava em sua versão 16.7.0. No momento da tradução, ele se encontra em sua versão 18.2.0 e houve muitas mudanças no comportamento dos componentes – em especial, com a questão de roteamento. Caso deseje realizar o processo ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-aplicacao-em-tempo-real-usando-socket-io-react-node-e-mongodb/</link>
                <guid isPermaLink="false">651893a9f57fe803e4aa2db2</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Giálisson Rocha ]]>
                </dc:creator>
                <pubDate>Tue, 09 Apr 2024 12:18:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/1_j_kShofJmfZ_-bEpt1IS8Q.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-create-a-realtime-app-using-socket-io-react-node-mongodb-a10c4a1ab676/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to create a realtime app using Socket.io, React, Node &amp; MongoDB</a>
      </p><blockquote>Nota da tradução: o artigo a seguir foi escrito quando o React estava em sua versão 16.7.0. No momento da tradução, ele se encontra em sua versão 18.2.0 e houve muitas mudanças no comportamento dos componentes – em especial, com a questão de roteamento. Caso deseje realizar o processo tal e qual ele está neste artigo, sugerimos a instalação da versão 16.7.0 do React para seguir o passo a passo. Para isso, use o comando <code>npm install react@16.7.0</code>.</blockquote><p>Você já se perguntou como as aplicações em tempo real são criadas? Já percebeu a importância e os casos de uso de aplicações em tempo real?</p><p>Se você está curioso sobre as perguntas acima e precisa de respostas, então este artigo é para você.</p><p>Primeiro, vamos identificar alguns casos de uso que precisam de aplicações em tempo real:</p><ol><li>Obter atualizações de localização do seu táxi em um mapa de uma aplicação de reserva de táxi.</li><li>Receba novas mensagens instantaneamente em sua aplicação de bate-papo favorito.</li><li>Atualização de informações sobre pedidos de comida para a cozinha de seu restaurante favorito.</li></ol><p>Todos esses são cenários comuns do nosso dia a dia, em que não podemos tolerar um atraso na atualização das informações e, portanto, precisamos de comunicação em tempo real.</p><p><strong>Tecnologias</strong> que podem ser usadas para <strong>comunicação em tempo real</strong> são:</p><ol><li><strong>Short Polling</strong>: AJAX, cria tráfego intenso.</li><li><strong>Long Polling</strong>: Igual ao AJAX, mas o servidor retém a resposta até que tenha uma atualização. Depois de recebê-la, o <em>client</em> envia outra solicitação e precisa que o cabeçalho adicional seja percorrido para frente e para trás, causando sobrecarga adicional.</li><li><strong>Web Sockets</strong>: possibilitam a abertura de comunicação interativa entre o <em>client</em> e o servidor. É possível enviar uma solicitação para o servidor e receber respostas orientadas por eventos sem consultar o servidor para obter uma resposta, o que torna os <em>Web Sockets</em> a <strong>melhor opção</strong> para o nosso caso de uso.</li></ol><p>Informações mais detalhadas sobre as três tecnologias acima podem ser lidas <a href="https://stackoverflow.com/questions/12555043/my-understanding-of-http-polling-long-polling-http-streaming-and-websockets" rel="noopener">aqui</a> (texto em inglês).</p><p>Vamos aprender a criar uma aplicação em tempo real, abordando o seguinte cenário: imagine que você está sentado em seu restaurante favorito e tem um menu digital. Você faz o pedido e a cozinha é atualizada sobre ele em tempo real. Quando a cozinha termina de fazer o pedido, ela também o atualiza em tempo real.</p><p>Características detalhadas:</p><ol><li><strong>Realizar o pedido</strong>: interface para selecionar a quantidade e fazer o pedido de um item alimentar selecionado para a cozinha.</li><li><strong>Cozinha</strong>: interface que pode ser aberta em várias cozinhas e atualiza em tempo real os chefs e cozinheiros com relação ao total de pedidos criados e à quantidade prevista de itens alimentícios, dando a eles a flexibilidade de atualizá-los. Também possui uma funcionalidade para baixar o relatório na forma de uma planilha do Excel.</li><li><strong>Mudança prevista</strong>: interface para atualizar a quantidade prevista de itens alimentares.</li></ol><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/03/6EyW3Wo0cKhjTFMskVgaWeTAaVS-3m26bhzL.gif" class="kg-image" alt="6EyW3Wo0cKhjTFMskVgaWeTAaVS-3m26bhzL" width="800" height="360" loading="lazy"></figure><p>Para uma melhor compreensão, abra-o em diferentes abas/dispositivos ao mesmo tempo para ver a alteração dos dados em tempo real.</p><p><strong>O código-fonte</strong> está <a href="https://github.com/honey93/OrderKitchen" rel="noopener">aqui</a>. Sinta-se à vontade para criar algo inovador/útil com base nele.</p><p>Então, vamos começar.</p><h3 id="stack-de-tecnologias-">Stack de tecnologias:</h3><p><strong>Front-end</strong>: React.js, Reactstrap, Socket.io</p><p><strong>Back-end</strong>: Node.js (Express), MongoDB, Socket.io</p><h3 id="estrutura-de-pastas-">Estrutura de pastas:</h3><pre><code>/*
Vá para o diretório raiz no código-fonte e encontre os arquivos mencionados abaixo. Essa arquitetura ajuda a criar uma grande aplicação modular.
*/
backend-my-app/ /* Código do back-end da aplicação */
 server.js       /* O código do soquete e do back-end fica aqui*/
 build/      /* Opcional para a implementação da build do front-end */ 
 package.json /* Dependências do back-end */
 ...
public/
src/  /*      Código-fonte do front-end      */
 global/      /*   Componentes usados em todos os lugares   */
  header.css
  header.js     
 main/           
  Kitchen.js
  PlaceOrder.js
  UpdatePredicted.js
 App.js   /* Lógica de roteamento e parte de montagem dos componentes */
package.json /* Dependências do front-end */ 
 ............</code></pre><h3 id="explica-o-do-c-digo-fonte-">Explicação do código-fonte:</h3><h4 id="front-end-">Front-end:</h4><pre><code>git clone https://github.com/honey93/OrderKitchen.git
cd OrderKitchen
npm install
npm start</code></pre><p>Pacotes utilizados:</p><ol><li><a href="https://reactstrap.github.io/" rel="noopener"><strong>Reactstrap</strong></a>: componentes do bootstrap 4 fáceis de usar.</li><li><a href="https://socket.io/docs/" rel="noopener"><strong>Socket.io</strong></a>: o Socket.io é uma biblioteca que permite a comunicação em tempo real, bidirecional e baseada em eventos entre o navegador e o servidor.</li><li><a href="https://www.npmjs.com/package/react-html-table-to-excel" rel="noopener"><strong>react-html-table-to-excel</strong></a>: fornece uma geração de arquivos Excel (.xls) no lado do <em>client</em> a partir de um elemento de tabela HTML.</li><li><a href="https://www.npmjs.com/package/react-router-dom" rel="noopener"><strong>react-router-dom</strong></a>: vinculações do DOM para o React Router. Ele consiste em vários componentes importantes, como BrowserRouter, usado quando há um servidor para lidar com solicitações dinâmicas, Switch, Route etc.</li></ol><h4 id="componente-app">Componente App</h4><p><strong>Caminho</strong>: <code>src/App.js</code></p><p>Este componente contém a lógica de roteamento principal do front-end. Esse arquivo é usado em src/index.js dentro do módulo Browser Router. O código abaixo demonstra uma das abordagens para manter sua aplicação modular.</p><pre><code class="language-javascript">import React, { Component } from "react";
import "./App.css";
import { Header } from "./global/header";
import { Switch, Route } from "react-router-dom";
import PlaceOrder from "./main/PlaceOrder";
import UpdatePredicted from "./main/UpdatePredicted";
import Kitchen from "./main/Kitchen";
/*O componente &lt;Route&gt; é a parte principal do React Router. Em qualquer lugar em que você queira renderizar apenas o conteúdo com base no nome do caminho do local, você deve usar um elemento &lt;Route&gt;. */
/* O componente Route espera uma propriedade de caminho, que é uma cadeia de caracteres que descreve o nome do caminho ao qual a rota corresponde */
/* O &lt;Switch&gt; iterará as rotas e renderizará apenas a primeira que corresponder ao nome do caminho atual */
class App extends Component {
  render() {
    return (
      &lt;div className="App"&gt;
        &lt;Header /&gt;
        &lt;Switch&gt;
          &lt;Route exact path="/" component={PlaceOrder} /&gt;
          &lt;Route path="/updatepredicted" component={UpdatePredicted} /&gt;
          &lt;Route path="/kitchen" component={Kitchen} /&gt;
        &lt;/Switch&gt;
      &lt;/div&gt;
    );
  }
}
export default App;</code></pre><h4 id="componente-do-cabe-alho">Componente do cabeçalho</h4><p><strong>Caminho</strong>: <code>src/global/header.js</code></p><p>Este componente será comum e usado em todas as seções, como Realizar Pedido (em inglês, <em>Place Order</em>), Mudança Prevista (em inglês, <em>Change Predicted</em>), Cozinha (em inglês, <em>Kitchen</em>). Essa abordagem ajuda a evitar a duplicação de código e mantém a aplicação modular.</p><pre><code class="language-js">import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import socketIOClient from "socket.io-client";
import "./header.css";
// O cabeçalho cria links que podem ser usados para navegar
// entre as rotas.
var socket;
class Header extends Component {
/* Cria um client do Socket e o exporta no final para ser usado nos componentes Place Order, Kitchen etc. */
  constructor() {
    super();
    this.state = {
      endpoint: 'http://localhost:3001/'
    };
socket = socketIOClient(this.state.endpoint);
  }
render() {
    return (
      &lt;header&gt;
        &lt;nav&gt;
          &lt;ul className="NavClass"&gt;
            &lt;li&gt;
              &lt;NavLink exact to="/"&gt;
                Place Order
              &lt;/NavLink&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;NavLink to="/updatepredicted"&gt;Change Predicted &lt;/NavLink&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;NavLink to="/kitchen"&gt; Kitchen &lt;/NavLink&gt;
            &lt;/li  &gt;
          &lt;/ul&gt;
        &lt;/nav&gt;
      &lt;/header&gt;
    );
  }
}
export { Header, socket };</code></pre><h4 id="componente-da-cozinha">Componente da cozinha</h4><p><strong>Caminho</strong>: <code>src/main/Kitchen.js</code></p><p>A lógica da UI da tela da Cozinha e o código html residem neste componente:</p><pre><code class="language-js">import React, { Component } from "react";
import { Button, Table, Container } from "reactstrap";
import { socket } from "../global/header";
import ReactHTMLTableToExcel from "react-html-table-to-excel";
class Kitchen extends Component {
  constructor() {
    super();
    this.state = {
      food_data: []
      // é onde estamos nos conectando com os soquetes,
    };
  }
getData = foodItems =&gt; {
    console.log(foodItems);
    this.setState({ food_data: foodItems });
  };
changeData = () =&gt; socket.emit("initial_data");
/* Assim que o componente for montado, ou seja, no método componentDidMount, dispara o evento initial_data para obter os dados para inicializar o Kitchen Dashboard */
/* Adiciona o ouvinte change_data para ouvir todas as alterações feitas pelos componentes Fazer pedido e Pedido previsto */ 
componentDidMount() {
    var state_current = this;
    socket.emit("initial_data");
    socket.on("get_data", this.getData);
    socket.on("change_data", this.changeData);
  }

/* Remove o ouvinte antes de desmontar o componente para evitar a adição de vários ouvintes no momento da revisão */
componentWillUnmount() {
    socket.off("get_data");
    socket.off("change_data");
  }
/* Quando Done (Pronto) é clicado, essa função é chamada e o evento mark_done é emitido, o qual é ouvido no back-end, explicado mais adiante*/
markDone = id =&gt; {
    // console.log(predicted_details);
    socket.emit("mark_done", id);
  };
getFoodData() {
    return this.state.food_data.map(food =&gt; {
      return (
        &lt;tr key={food._id}&gt;
          &lt;td&gt; {food.name} &lt;/td&gt;
          &lt;td&gt; {food.ordQty} &lt;/td&gt;
          &lt;td&gt; {food.prodQty} &lt;/td&gt;
          &lt;td&gt; {food.predQty} &lt;/td&gt;
          &lt;td&gt;
            &lt;button onClick={() =&gt; this.markDone(food._id)}&gt;Done&lt;/button&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      );
    });
  }
render() {
    return (
      &lt;Container&gt;
        &lt;h2 className="h2Class"&gt;Kitchen Area&lt;/h2&gt;
        &lt;ReactHTMLTableToExcel
          id="test-table-xls-button"
          className="download-table-xls-button"
          table="table-to-xls"
          filename="tablexls"
          sheet="tablexls"
          buttonText="Download as XLS"
        /&gt;
&lt;Table striped id="table-to-xls"&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Name&lt;/th&gt;
              &lt;th&gt;Quantity&lt;/th&gt;
              &lt;th&gt;Created Till Now&lt;/th&gt;
              &lt;th&gt;Predicted&lt;/th&gt;
              &lt;th&gt;Status&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;{this.getFoodData()}&lt;/tbody&gt;
        &lt;/Table&gt;
      &lt;/Container&gt;
    );
  }
}
export default Kitchen;</code></pre><h4 id="componente-fazer-pedido">Componente Fazer Pedido</h4><p><strong>Caminho</strong>: <code>src/main/PlaceOrder.js</code></p><pre><code class="language-js">import React, { Component } from "react";
import { Button, Table, Container } from "reactstrap";
import { socket } from "../global/header";
class PlaceOrder extends Component {
  constructor() {
    super();
    this.state = {
      food_data: []
      // é onde estamos nos conectando com os soquetes,
    };
  }
getData = foodItems =&gt; {
    console.log(foodItems);
    foodItems = foodItems.map(food =&gt; {
      food.order = 0;
return food;
    });
    this.setState({ food_data: foodItems });
  };
componentDidMount() {
    socket.emit("initial_data");
    var state_current = this;
    socket.on("get_data", state_current.getData);
  }
componentWillUnmount() {
    socket.off("get_data", this.getData);
  }
// Função para fazer o pedido.
sendOrder = id =&gt; {
    var order_details;
    this.state.food_data.map(food =&gt; {
      if (food._id == id) {
        order_details = food;
      }
      return food;
    });
    console.log(order_details);
    socket.emit("putOrder", order_details);
    var new_array = this.state.food_data.map(food =&gt; {
      food.order = 0;
      return food;
    });
    this.setState({ food_data: new_array });
  };
// Altera a quantidade no estado que é emitido para o back-end no momento da realização do pedido.
changeQuantity = (event, foodid) =&gt; {
    if (parseInt(event.target.value) &lt; 0) {
      event.target.value = 0;
    }
    var new_array = this.state.food_data.map(food =&gt; {
      if (food._id == foodid) {
        food.order = parseInt(event.target.value);
      }
      return food;
    });
    this.setState({ food_data: new_array });
  };
// Obtém os dados iniciais
getFoodData() {
    return this.state.food_data.map(food =&gt; {
      return (
        &lt;tr key={food._id}&gt;
          &lt;td&gt; {food.name} &lt;/td&gt;
          &lt;td&gt;
            &lt;input
              onChange={e =&gt; this.changeQuantity(e, food._id)}
              value={food.order}
              type="number"
              placeholder="Quantity"
            /&gt;
          &lt;/td&gt;
          &lt;td&gt;
            &lt;button onClick={() =&gt; this.sendOrder(food._id)}&gt;Order&lt;/button&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      );
    });
  }
render() {
    return (
      &lt;Container&gt;
        &lt;h2 className="h2Class"&gt;Order Menu&lt;/h2&gt;
        &lt;Table striped&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Product&lt;/th&gt;
              &lt;th&gt;Quantity&lt;/th&gt;
              &lt;th&gt;Order&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;{this.getFoodData()}&lt;/tbody&gt;
        &lt;/Table&gt;
      &lt;/Container&gt;
    );
  }
}
export default PlaceOrder;</code></pre><p>Mais uma seção chamada Atualizar caminho previsto (em inglês, <em>Update Predicted Path</em>): <code>src/main/UpdatePredicted.js</code>, semelhante à seção acima, está no repositório de código.</p><h3 id="back-end">Back-end</h3><p>Iniciando o back-end:</p><pre><code>cd backend-my-app
npm install
node server.js</code></pre><p>Pacotes utilizados:</p><ol><li><a href="https://www.npmjs.com/package/monk" rel="noopener"><strong>Monk</strong></a>: uma pequena camada que oferece melhorias simples, mas substanciais, na usabilidade do uso do MongoDB no Node.JS.</li><li><a href="https://socket.io/docs/" rel="noopener"><strong>Socket.io</strong></a>: o Socket.io é uma biblioteca que permite a comunicação em tempo real, bidirecional e baseada em eventos entre o navegador e o servidor.</li></ol><p>3. <a href="https://www.npmjs.com/package/express" rel="noopener"><strong>Express</strong></a>: estrutura da Web rápida e minimalista para o <a href="http://nodejs.org/" rel="noopener">node</a>.</p><h4 id="c-digo-principal">Código principal</h4><p><strong>Caminho</strong>: <code>backend-my-app/server.js</code></p><pre><code class="language-js">const express = require("express");
const http = require("http");
const socketIO = require("socket.io");
// Cadeia de conexão do banco de dados MongoDb hospedado no Mlab ou localmente
var connection_string = "**********";
// O nome da coleção deve ser "FoodItems", pois há apenas uma coleção no momento.
// O formato do documento deve ser o mencionado abaixo, pelo menos um desses documentos:
// {
//     "_id": {
//         "$oid": "5c0a1bdfe7179a6ca0844567"
//     },
//     "name": "Veg Roll",
//     "predQty": 100,
//     "prodQty": 295,
//     "ordQty": 1
// }
const db = require("monk")(connection_string);
const collection_foodItems = db.get("FoodItems");
// nossa porta do localhost
const port = process.env.PORT || 3000;
const app = express();
// nossa instância de servidor
const server = http.createServer(app);
// Isso cria nosso soquete usando a instância do servidor
const io = socketIO(server);
io.on("connection", socket =&gt; {
// console.log("New client connected" + socket.id);
// console.log(socket);
// Retornando os dados iniciais do menu de comida da coleção FoodItems
  socket.on("initial_data", () =&gt; {
    collection_foodItems.find({}).then(docs =&gt; {
      io.sockets.emit("get_data", docs);
    });
  });
// A realização do pedido é chamada em /src/main/PlaceOrder.js do Frontend
  socket.on("putOrder", order =&gt; {
    collection_foodItems
      .update({ _id: order._id }, { $inc: { ordQty: order.order } })
      .then(updatedDoc =&gt; {
        // Emissão de evento para atualizar a Cozinha aberta nos dispositivos com os valores do pedido em tempo real
        io.sockets.emit("change_data");
      });
  });
// Conclusão do pedido, chamada a partir de /src/main/Kitchen.js
  socket.on("mark_done", id =&gt; {
    collection_foodItems
      .update({ _id: id }, { $inc: { ordQty: -1, prodQty: 1 } })
      .then(updatedDoc =&gt; {
        // Atualizar as diferentes áreas da cozinha com o status atual.
        io.sockets.emit("change_data");
      });
  });

// Funcionalidade para alterar o valor da quantidade prevista, chamada de /src/main/UpdatePredicted.js
  socket.on("ChangePred", predicted_data =&gt; {
    collection_foodItems
      .update(
        { _id: predicted_data._id },
        { $set: { predQty: predicted_data.predQty } }
      )
      .then(updatedDoc =&gt; {
        // Evento de soquete para atualizar a quantidade prevista na cozinha
        io.sockets.emit("change_data");
      });
  });

// A desconexão é acionada quando um cliente deixa o servidor
  socket.on("disconnect", () =&gt; {
    console.log("user disconnected");
  });
});
/* As etapas mencionadas abaixo são executadas para retornar a compilação do Front-end do create-react-app da pasta de compilação do Back-end.*/
app.use(express.static("build"));
app.use("/kitchen", express.static("build"));
app.use("/updatepredicted", express.static("build"));
server.listen(port, () =&gt; console.log(`Listening on port ${port}`));</code></pre><p><strong>Banco de dados</strong>: MongoDB</p><p><a href="https://mlab.com/" rel="noopener"><strong>Mlab</strong></a>: banco de dados como um serviço para o MongoDB</p><p><strong>Nome da coleção</strong>: FoodItems</p><p><strong>Formato do documento</strong>: é necessário pelo menos um documento na coleção FoodItems com o formato mencionado abaixo.</p><pre><code class="language-js">{
"name": "Veg Roll",  // Nome do alimento
"predQty": 100,  // Quantidade prevista
"prodQty": 295,  // Quantidade produzida
"ordQty": 1   // Quantidade total do pedido
}</code></pre><p>Espero que você tenha entendido como criar uma aplicação modular em tempo real usando a pilha MERN. Se você achou útil, deixe uma <strong>estrela</strong> no <a href="https://github.com/honey93/OrderKitchen" rel="noopener">repositório do GitHub</a> do projeto e compartilhe com seus amigos também.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
