One place for hosting & domains

      escrever

      Como escrever um código assíncrono em Node.js


      O autor selecionou a Open Internet/Free Speech Fund para receber uma doação como parte do programa Write for DOnations.

      Introdução

      Com muitos programas em JavaScript, o código é executado da maneira como o programador o escreveu — linha por linha. A isto chamamos de execução síncrona, pois as linhas são executadas uma após a outra, na ordem em que foram escritas. No entanto, nem toda instrução que você dá ao computador precisa ser atendida imediatamente. Por exemplo, caso envie uma solicitação de rede, o processo que executa seu código terá que esperar pelo retorno dos dados, antes de poder trabalhar neles. Nesse caso, seria um desperdício de tempo se o computador não executasse outro código enquanto aguarda a solicitação da rede ser concluída. Para resolver esse problema, os desenvolvedores usam a programação assíncrona, na qual as linhas do código são executadas em uma ordem diferente daquela em que foram escritas. Com a programação assíncrona, podemos executar outros códigos enquanto esperamos por atividades longas terminarem, como os pedidos de rede.

      O código JavaScript é executado em um único thread dentro de um processo de computador. Seu código é processado de maneira sincronizada nesse thread, com apenas uma instrução sendo executada por vez. Portanto, caso fôssemos realizar uma tarefa de execução demorada nesse thread, todo o código restante ficaria bloqueado até que a tarefa estivesse concluída. Para evitar esse problema, podemos aproveitar-nos dos recursos de programação assíncrona do JavaScript, descarregando tarefas de execução demorada em um thread em segundo plano. Quando a tarefa é concluída, o código que precisamos para processar os dados da tarefa é colocado de volta no thread único principal.

      Neste tutorial, você aprenderá como o JavaScript gerencia tarefas assíncronas com a ajuda do Loop de eventos, que consiste em um constructo do JavaScript que conclui uma nova tarefa enquanto aguarda por outra. Depois, criará um programa que utilize a programação assíncrona para solicitar uma lista de filmes de uma API do Studio Ghibli e salvará os dados em um arquivo CSV. O código assíncrono será escrito de três maneiras: callbacks (retornos de chamadas), promises (promessas) e com as palavras-chave async/await.

      Nota: no momento desta publicação, a programação assíncrona não é mais feita usando apenas com os callbacks. Entretanto, aprender esse método obsoleto pode proporcionar um ótimo contexto quanto ao motivo pelo qual a comunidade JavaScript agora usa as promises. As palavras-chave async/await nos permitem usar as promises de uma maneira menos detalhada. Assim, no momento em que este artigo foi escrito, essa era a maneira padrão de se fazer a programação assíncrona em JavaScript.

      Pré-requisitos

      O loop de eventos

      Vamos começar estudando o funcionamento interno da execução de funções em JavaScript. Entender como as funções se comportam permitirá que você escreva um código assíncrono de maneira mais consciente, bem como ajudará você a solucionar problemas do código no futuro.

      À medida que o programa interpretador de JavaScript executa o código, cada função que é chamada é adicionada à pilha de chamadas do JavaScript. A pilha de chamadas é uma* pilha* — uma estrutura de dados do tipo lista, na qual os itens apenas podem ser adicionados ao topo e removidos do topo. As pilhas seguem o princípio “Último a entrar, primeiro a sair”, ou princípio LIFO (do inglês “Last in, first out”). Se adicionar dois itens na pilha, o item adicionado por último será removido primeiro.

      Vamos ilustrar com um exemplo usando a pilha de chamadas. Se o JavaScript encontra uma função functionA() sendo chamada, ela é adicionada à pilha de chamadas. Se essa função, functionA() chama outra função, functionB(), então a functionB() é adicionada ao topo da pilha de chamadas. À medida que o JavaScript completa a execução de uma função, ela é removida da pilha de chamadas. Portanto, o JavaScript executará a functionB() primeiro, irá removê-la da pilha quando terminar para, então, terminar a execução da functionA() e remover esta da pilha de chamadas. É por isso que as funções internas são sempre executadas antes de suas funções externas.

      Quando o JavaScript encontra uma operação assíncrona, como gravar algo em um arquivo, ele adiciona essa operação a uma tabela de sua memória. Essa tabela armazena a operação, a condição para que ela seja completada e a função a ser chamada quando ela for concluída. Quando a operação é concluída, o JavaScript adiciona a função associada à fila de mensagens. Uma fila é outra estrutura de dados do tipo lista. Nela, os itens apenas podem ser adicionados ao final, mas removidos do topo. Na fila de mensagens, se duas ou mais operações assíncronas estiverem prontas para que suas funções sejam executadas, a operação assíncrona que foi concluída primeiro terá sua função marcada para executar primeiro.

      As funções na fila de mensagens estão esperando para serem adicionadas à pilha de chamadas. O loop de eventos é um processo contínuo que verifica se a pilha de chamadas está vazia. Se estiver, então o primeiro item na fila de mensagens é movido para a pilha de chamadas. O JavaScript prioriza as funções na fila de mensagens, em detrimento das chamadas de função que ele interpreta no código. O efeito combinado da pilha de chamadas, da fila de mensagens e do loop de eventos permite que código em JavaScript seja processado enquanto gerencia as atividades assíncronas.

      Agora que possui uma comprensão abrangente sobre o loop de eventos, você sabe como o código assíncrono que você escrever será executado. Com esse conhecimento, agora você pode criar um código assíncrono com três abordagens diferentes: callbacks, promises e async/await.

      Uma função callback é aquela que é enviada para outra função como um argumento e, em seguida, é executada – quando a outra função tiver sido finalizada. Usamos as callbacks para garantir que o código somente será executado depois da conclusão de uma operação assíncrona.

      Por muito tempo, os callbacks foram o mecanismo mais comum para se escrever códigos assíncronos. Agora, porém, eles se tornaram, em grande parte, obsoletos, uma vez que podem tornar um código confuso para ler. Neste passo, você escreverá um exemplo de código assíncrono usando callbacks, de modo que você possa usá-lo como um parâmetro de comparação para perceber a eficiência das demais estratégias.

      Existem muitas maneiras de se usar as funções de callback em outra função. Geralmente, elas adotam esta estrutura:

      function asynchronousFunction([ Function Arguments ], [ Callback Function ]) {
          [ Action ]
      }
      

      Embora nem o JavaScript nem o Node.js tenham a exigência sintática de trazer a função de callback como o último argumento da função externa, trata-se de uma prática comum para facilitar a identificação dos callbacks. Também é comum para os desenvolvedores em JavaScript usar uma função anônima como um callback. As funções anônimas são aquelas criadas sem um nome. Normalmente, uma função fica muito mais legível quando definida no final da lista de argumentos.

      Para demonstrar os callbacks, vamos criar um módulo do Node.js que grava uma lista dos filmes do Studio Ghibli em um arquivo. Primeiro, crie uma pasta que armazenará nosso arquivo JavaScript e seu resultado:

      Então, acesse aquela pasta:

      Começaremos fazendo uma solicitação HTTP à API do Studio Ghibli, da qual nossa função de callback registrará os resultados. Para tanto, instalaremos uma biblioteca que nos permitirá acessar os dados de uma resposta do HTTP em um callback.

      No seu terminal, inicialize o npm para termos uma referência para nossos pacotes mais tarde:

      Em seguida, instale a biblioteca request (solicitação):

      Agora, abra um novo arquivo chamado callbackMovies.js em um editor de texto como o nano:

      No seu editor de texto, digite o código a seguir. Vamos começar enviando uma solicitação HTTP com o módulo request:

      callbackMovies.js

      const request = require('request');
      
      request('https://ghibliapi.herokuapp.com/films');
      

      Na primeira linha, carregaremos o módulo request – o qual foi instalado via npm [NT: gerenciador de pacotes para a linguagem de programação JavaScript]. O módulo retorna uma função que pode fazer pedidos via HTTP; então, salvamos essa função na constante request.

      Depois, realizamos a solicitação HTTP usando a função request(). Agora, vamos imprimir os dados da solicitação HTTP no console, adicionando as alterações destacadas:

      callbackMovies.js

      const request = require('request');
      
      request('https://ghibliapi.herokuapp.com/films', (error, response, body) => {
          if (error) {
              console.error(`Could not send request to API: ${error.message}`);
              return;
          }
      
          if (response.statusCode != 200) {
              console.error(`Expected status code 200 but received ${response.statusCode}.`);
              return;
          }
      
          console.log('Processing our list of movies');
          movies = JSON.parse(body);
          movies.forEach(movie => {
              console.log(`${movie['title']}, ${movie['release_date']}`);
          });
      });
      

      Quando usamos a função request(), damos a ela dois parâmetros:

      • O URL do site que estamos tentando solicitar
      • Uma função de callback que lide com erros ou respostas bem-sucedidas depois que a solicitação for concluída

      Nossa função de callback tem três argumentos: error (erro), response (reposta) e body (corpo). Quando a solicitação HTTP é concluída, os argumentos recebem valores automaticamente, dependendo do resultado. Caso houvesse falha no envio da solicitação, então o error conteria um objeto, mas o argumento response e body seriam null (nulo). Se o pedido fosse bem-sucedido, então a resposta HTTP seria armazenada em response. Se nossa resposta HTTP retornasse dados (neste exemplo, obtivemos JSON), então os dados seriam definidos em body.

      Primeiro, nossa função de callback verifica se recebemos um erro. Verificar primeiro se há erros em um callback é uma boa prática. Dessa maneira, a execução do callback não continuará com dados faltando. Neste caso, registramos o erro e a execução da função. Em seguida, verificamos o código do status da resposta. Nem sempre nosso servidor pode estar disponível e as APIs podem sofrer alterações, fazendo com que solicitações, antes adequadas, tornem-se incorretas. Ao verificar se o código de status é 200 – que significa que o pedido estava “OK”, podemos confiar que nossa resposta será a que esperamos que seja.

      Por fim, analisamos o corpo da resposta em uma Array (matriz) e executamos um loop em cada filme para registrar seu nome e ano de lançamento.

      Após salvar e sair do arquivo, execute este script com:

      Você receberá o seguinte resultado:

      Output

      Castle in the Sky, 1986 Grave of the Fireflies, 1988 My Neighbor Totoro, 1988 Kiki's Delivery Service, 1989 Only Yesterday, 1991 Porco Rosso, 1992 Pom Poko, 1994 Whisper of the Heart, 1995 Princess Mononoke, 1997 My Neighbors the Yamadas, 1999 Spirited Away, 2001 The Cat Returns, 2002 Howl's Moving Castle, 2004 Tales from Earthsea, 2006 Ponyo, 2008 Arrietty, 2010 From Up on Poppy Hill, 2011 The Wind Rises, 2013 The Tale of the Princess Kaguya, 2013 When Marnie Was There, 2014

      Felizmente, recebemos uma lista dos filmes do Studio Ghibli, contendo o ano em que foram lançados. Agora, vamos completar esse programa, escrevendo a lista de filmes que estamos registrando em um arquivo no momento.

      Atualize o arquivo callbackMovies.js em seu editor de texto, de modo a incluir o seguinte código destacado, o qual cria um arquivo CSV com os nossos dados dos filmes:

      callbackMovies.js

      const request = require('request');
      const fs = require('fs');
      
      request('https://ghibliapi.herokuapp.com/films', (error, response, body) => {
          if (error) {
              console.error(`Could not send request to API: ${error.message}`);
              return;
          }
      
          if (response.statusCode != 200) {
              console.error(`Expected status code 200 but received ${response.statusCode}.`);
              return;
          }
      
          console.log('Processing our list of movies');
          movies = JSON.parse(body);
          let movieList = '';
          movies.forEach(movie => {
              movieList += `${movie['title']}, ${movie['release_date']}n`;
          });
      
          fs.writeFile('callbackMovies.csv', movieList, (error) => {
              if (error) {
                  console.error(`Could not save the Ghibli movies to a file: ${error}`);
                  return;
              }
      
              console.log('Saved our list of movies to callbackMovies.csv');;
          });
      });
      

      Ao notar as alterações destacadas, vemos que importamos o módulo fs. Esse módulo é padrão em todas as instalações do Node.js e contém um método writeFile() que pode escrever em um arquivo de maneira assíncrona.

      Em vez de registrar os dados no console, agora nós vamos adicioná-los a uma variável de string – movieList. Então, usamos o writeFile() para salvar o conteúdo da movieList em um novo arquivo — callbackMovies.csv. Por fim, fornecemos um callback à função writeFile(), que tem um argumento: error. Isso nos permite lidar com casos em que não conseguimos escrever em um arquivo, como, por exemplo, quando o usuário em que estamos executando o processo node não tem essas permissões.

      Salve o arquivo e execute esse programa Node.js novamente com:

      Em sua pasta ghibliMovies, você verá o callbackMovies.csv, que tem o seguinte conteúdo:

      callbackMovies.csv

      Castle in the Sky, 1986
      Grave of the Fireflies, 1988
      My Neighbor Totoro, 1988
      Kiki's Delivery Service, 1989
      Only Yesterday, 1991
      Porco Rosso, 1992
      Pom Poko, 1994
      Whisper of the Heart, 1995
      Princess Mononoke, 1997
      My Neighbors the Yamadas, 1999
      Spirited Away, 2001
      The Cat Returns, 2002
      Howl's Moving Castle, 2004
      Tales from Earthsea, 2006
      Ponyo, 2008
      Arrietty, 2010
      From Up on Poppy Hill, 2011
      The Wind Rises, 2013
      The Tale of the Princess Kaguya, 2013
      When Marnie Was There, 2014
      

      É importante notar que estamos escrevendo em nosso arquivo CSV no callback da solicitação HTTP. Assim que o código estiver na função de callback, ele apenas gravará no arquivo após a solicitação HTTP ser finalizada. Se quiséssemos nos comunicar com um banco de dados – depois de termos escrito nosso arquivo CSV, faríamos outra função assíncrona, a qual seria chamada no callback da função writeFile(). Quanto mais código assíncrono tivermos, mais funções de callback precisam ser aninhadas.

      Imaginemos um cenário em que queiramos executar cinco operações assíncronas, cada uma podendo ser executada apenas quando outra for concluída. Se tivéssemos que codificar isso, teríamos algo parecido com o seguinte:

      doSomething1(() => {
          doSomething2(() => {
              doSomething3(() => {
                  doSomething4(() => {
                      doSomething5(() => {
                          // final action
                      });
                  });
              });
          });
      });
      

      Quando os callbacks aninhados têm muitas linhas de código a serem executadas, eles se tornam consideravelmente mais complexos e ilegíveis. À medida que seu projeto JavaScript cresce em tamanho e complexidade, esse efeito se tornará mais visível, até que, no final das contas, ele se torna não gerenciável. Por isso, os desenvolvedores não usam mais callbacks para lidar com operações assíncronas. Para melhorar a sintaxe do nosso código assíncrono, podemos usar promises como alternativa.

      Usando promises para obter uma programação assíncrona concisa

      Uma promise é um objeto JavaScript que retornará um valor em algum momento no futuro. As funções assíncronas podem retornar objetos promise, em vez de valores concretos. Se recebermos um valor no futuro, dizemos que a promessa (promise) foi cumprida. Se recebermos um erro no futuro, dizemos que a promessa foi rejeitada. Caso contrário, a promessa ainda estará sendo trabalhada em um estado pendente.

      As promises geralmente adotam a seguinte forma:

      promiseFunction()
          .then([ Callback Function for Fulfilled Promise ])
          .catch([ Callback Function for Rejected Promise ])
      

      Como mostrado nesse modelo, as promises também usam funções de callback. Temos uma função de callback para o método then(), que é executado quando uma promise é realizada. Também temos uma função de callback para o método catch() para lidar com todo erro que aparecer enquanto a promessa é executada.

      Vamos ter uma experiência direta com as promises, reescrevendo nosso programa do Studio Ghibli para que use promises como alternativa.

      O Axios é um cliente HTTP baseado em promises para JavaScript. Assim, vamos prosseguir e instalá-lo:

      Agora, com o editor de sua escolha, crie um novo arquivo promiseMovies.js:

      Nosso programa fará uma solicitação HTTP com o axios e depois usará uma versão especial do fs – baseada em promise – para salvar em um novo arquivo CSV.

      Digite este código em promiseMovies.js para que possamos carregar o Axios e enviar uma solicitação HTTP para a API de filmes:

      promiseMovies.js

      const axios = require('axios');
      
      axios.get('https://ghibliapi.herokuapp.com/films');
      

      Na primeira linha, carregamos o módulo axios, armazenando a função retornada em uma constante chamada axios. Em seguida, usamos o método axios.get() para enviar uma solicitação HTTP para a API.

      O método axios.get() retorna uma promise. Vamos encadear aquela promise para que possamos imprimir a lista dos filmes Ghibli no console:

      promiseMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      
      axios.get('https://ghibliapi.herokuapp.com/films')
          .then((response) => {
              console.log('Successfully retrieved our list of movies');
              response.data.forEach(movie => {
                  console.log(`${movie['title']}, ${movie['release_date']}`);
              });
          })
      

      Vamos detalhar o que está acontecendo. Após realizar uma solicitação HTTP GET com o axios.get(), usamos a função then(), que é executada apenas quando a promise é realizada. Neste caso, imprimimos os filmes na tela como fizemos no exemplo dos callbacks.

      Para melhorar esse programa, adicione o código destacado para escrever os dados HTTP em um arquivo:

      promiseMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      
      axios.get('https://ghibliapi.herokuapp.com/films')
          .then((response) => {
              console.log('Successfully retrieved our list of movies');
              let movieList = '';
              response.data.forEach(movie => {
                  movieList += `${movie['title']}, ${movie['release_date']}n`;
              });
      
              return fs.writeFile('promiseMovies.csv', movieList);
          })
          .then(() => {
              console.log('Saved our list of movies to promiseMovies.csv');
          })
      

      Além disso, importamos o módulo fs novamente. Note que, após a importação do fs, agora temos a extensão .promises. O Node.js inclui uma versão baseada em promises da biblioteca fs baseada em callbacks, de modo que a retrocompatibilidade não é quebrada em projetos herdados.

      A primeira função then() que processa a solicitação HTTP agora chama o fs.writeFile(), em vez de imprimir no console. Como importamos a versão baseada em promises do fs, nossa função writeFile() retorna outra promise. Desta forma, anexamos outra função then() para quando a promise da writeFile() for realizada.

      Uma promise pode retornar uma nova promise, permitindo que executemos promises uma após a outra. Isso nos possibilita realizar múltiplas operações assíncronas. Isso se chama encadeamento de promises, sendo comparáveis às callbacks aninhadas. O segundo then() é chamado apenas após gravarmos com sucesso no arquivo.

      Nota: neste exemplo, não verificamos o código de status do HTTP como fizemos no exemplo das callbacks. Por padrão, o axios não realiza duas promises caso receber um código de status indicando um erro. Desta forma, não precisamos mais validá-lo.

      Para completar esse programa, encadeie a promise com uma função catch(), como destacado a seguir:

      promiseMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      
      axios.get('https://ghibliapi.herokuapp.com/films')
          .then((response) => {
              console.log('Successfully retrieved our list of movies');
              let movieList = '';
              response.data.forEach(movie => {
                  movieList += `${movie['title']}, ${movie['release_date']}n`;
              });
      
              return fs.writeFile('promiseMovies.csv', movieList);
          })
          .then(() => {
              console.log('Saved our list of movies to promiseMovies.csv');
          })
          .catch((error) => {
              console.error(`Could not save the Ghibli movies to a file: ${error}`);
          });
      

      Se alguma promise deixar de ser realizada na cadeia de promises, o JavaScript automaticamente vai para a função catch() – caso ela tenha sido definida. É por isso que temos apenas uma cláusula catch(), apesar de termos duas operações assíncronas.

      Vamos confirmar se nosso programa produz o mesmo resultado, executando:

      Na sua pasta ghibliMovies, você verá o arquivo promiseMovies.csv, que contém:

      promiseMovies.csv

      Castle in the Sky, 1986
      Grave of the Fireflies, 1988
      My Neighbor Totoro, 1988
      Kiki's Delivery Service, 1989
      Only Yesterday, 1991
      Porco Rosso, 1992
      Pom Poko, 1994
      Whisper of the Heart, 1995
      Princess Mononoke, 1997
      My Neighbors the Yamadas, 1999
      Spirited Away, 2001
      The Cat Returns, 2002
      Howl's Moving Castle, 2004
      Tales from Earthsea, 2006
      Ponyo, 2008
      Arrietty, 2010
      From Up on Poppy Hill, 2011
      The Wind Rises, 2013
      The Tale of the Princess Kaguya, 2013
      When Marnie Was There, 2014
      

      Com as promises, podemos escrever um código muito mais conciso do que usando apenas callbacks. A cadeia de promises das callbacks é uma opção mais organizada do que o aninhamento de callbacks. No entanto, à medida que fazemos mais chamadas assíncronas, nossa cadeia de promises se torna mais longa e difícil de manter.

      O detalhamento das funções callbacks e promises vem da necessidade de se criar funções quando temos o resultado de uma tarefa assíncrona. Uma prática melhor seria aguardar por um resultado assíncrono e colocá-lo em uma variável fora da função. Dessa maneira, podemos usar os resultados nas variáveis sem ter que criar uma função. Podemos conseguir isso com as palavras-chave async e await.

      As palavras-chave async/await fornecem uma sintaxe alternativa ao trabalhar com promises. Em vez de ter o resultado de uma promise disponível no método then(), o resultado é retornado como um valor, assim como em qualquer outra função. Definimos uma função com a palavra-chave async para dizer ao JavaScript que é uma função assíncrona que retorna uma promise. Usamos a palavra-chave await para dizer ao JavaScript para retornar os resultados da promise, em vez de retornar a promise, propriamente dita, quanto ela for realizada.

      De um modo geral, o uso de async/await fica com a seguinte aparência:

      async function() {
          await [Asynchronous Action]
      }
      

      Vejamos de que maneira o uso de async/await pode melhorar nosso programa do Studio Ghibli. Use seu editor de texto para criar e abrir um novo arquivo asyncAwaitMovies.js:

      No seu arquivo em JavaScript recém-criado, vamos começar importando os mesmos módulos que usamos em nosso exemplo de promise:

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      

      As importações são as mesmas do promiseMovies.js, pois async/await usa promises.

      Agora, usamos a palavra-chave async para criar uma função com nosso código assíncrono:

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      async function saveMovies() {}
      

      Criamos uma nova função chamada saveMovies(), mas incluímos async no início de sua definição. Isso é importante, pois somente podemos usar a palavra-chave await em uma função assíncrona.

      Utilize a palavra-chave await para fazer uma solicitação HTTP que recebe a lista de filmes da API do Ghibli:

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      async function saveMovies() {
          let response = await axios.get('https://ghibliapi.herokuapp.com/films');
          let movieList = '';
          response.data.forEach(movie => {
              movieList += `${movie['title']}, ${movie['release_date']}n`;
          });
      }
      

      Em nossa função saveMovies(), fazemos uma solicitação HTTP com o axios.get(), como antes. Desta vez, não a encadearemos com uma função then(). Em vez disso, adicionamos await antes que ela seja chamada. Quando o JavaScript vê await, ele somente executará o código restante da função depois que a função axios.get() terminar a execução e definir a variável response. O outro código salva os dados dos filmes para que possamos gravar em um arquivo.

      Vamos gravar os dados dos filmes em um arquivo:

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      async function saveMovies() {
          let response = await axios.get('https://ghibliapi.herokuapp.com/films');
          let movieList = '';
          response.data.forEach(movie => {
              movieList += `${movie['title']}, ${movie['release_date']}n`;
          });
          await fs.writeFile('asyncAwaitMovies.csv', movieList);
      }
      

      Também usamos a palavra-chave await quando escrevemos no arquivo com fs.writeFile().

      Para completar essa função, precisamos capturar os erros que nossas promises podem gerar. Vamos fazer isso, encapsulando nosso código em um bloco try/catch (tentar/caputar):

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      async function saveMovies() {
          try {
              let response = await axios.get('https://ghibliapi.herokuapp.com/films');
              let movieList = '';
              response.data.forEach(movie => {
                  movieList += `${movie['title']}, ${movie['release_date']}n`;
              });
              await fs.writeFile('asyncAwaitMovies.csv', movieList);
          } catch (error) {
              console.error(`Could not save the Ghibli movies to a file: ${error}`);
          }
      }
      
      

      Como as promises podem falhar, envolvemos nosso código assíncrono com uma cláusula try/catch. Isso captará quaisquer erros que forem gerados quando as operações de solicitação HTTP ou as operações de gravação de arquivos falharem.

      Por fim, vamos chamar nossa função assíncrona saveMovies() para que ela seja executada quando executarmos o programa com o node.

      asyncAwaitMovies.js

      const axios = require('axios');
      const fs = require('fs').promises;
      
      async function saveMovies() {
          try {
              let response = await axios.get('https://ghibliapi.herokuapp.com/films');
              let movieList = '';
              response.data.forEach(movie => {
                  movieList += `${movie['title']}, ${movie['release_date']}n`;
              });
              await fs.writeFile('asyncAwaitMovies.csv', movieList);
          } catch (error) {
              console.error(`Could not save the Ghibli movies to a file: ${error}`);
          }
      }
      
      saveMovies();
      

      De imediato, o programa fica parecido com um bloco de código JavaScript síncrono típico. Ele tem menos funções sendo passadas, fazendo-o parecer mais organizado. Esses pequenos ajustes tornam o código assíncrono com async/await mais fáceis de manter.

      Teste essa iteração do nosso programa, digitando isto em seu terminal:

      Em sua pasta ghibliMovies, um novo arquivo asyncAwaitMovies.csv será criado com o seguinte conteúdo:

      asyncAwaitMovies.csv

      Castle in the Sky, 1986
      Grave of the Fireflies, 1988
      My Neighbor Totoro, 1988
      Kiki's Delivery Service, 1989
      Only Yesterday, 1991
      Porco Rosso, 1992
      Pom Poko, 1994
      Whisper of the Heart, 1995
      Princess Mononoke, 1997
      My Neighbors the Yamadas, 1999
      Spirited Away, 2001
      The Cat Returns, 2002
      Howl's Moving Castle, 2004
      Tales from Earthsea, 2006
      Ponyo, 2008
      Arrietty, 2010
      From Up on Poppy Hill, 2011
      The Wind Rises, 2013
      The Tale of the Princess Kaguya, 2013
      When Marnie Was There, 2014
      

      Agora, você usou os recursos async/await do JavaScript para gerenciar um código assíncrono.

      Conclusão

      Neste tutorial, você aprendeu como o JavaScript lida com a execução de funções e o gerenciamento de operações assíncronas com o loop de eventos. Na sequência, você escreveu programas que criaram um arquivo CSV depois de fazer uma solicitação HTTP por dados de filmes, usando várias técnicas de programação assíncrona. Primeiro, você usou a abordagem obsoleta baseada em callbacks. Então, usou promises e, por fim, async/await para tornar a sintaxe da promise mais sucinta.

      Com o conhecimento sobre códigos assíncronos com o Node.js, agora você pode desenvolver programas que se beneficiem da programação assíncrona, tais como aqueles que dependem de chamadas da API. Veja esta lista de APIs públicas. Para usá-las, você terá que fazer solicitações HTTP assíncronas, como fizemos neste tutorial. Para avançar nesse estudo, tente compilar um app que utilize essas APIs para praticar as técnicas que aprendeu aqui.



      Source link

      Como escrever comentários em Go


      Introdução

      Comentários são linhas que existem em programas de computador que os programas de compilação e interpretação ignoram. A inclusão de comentários nos programas torna o código mais legível para humanos, uma vez que fornece informações ou explicações sobre o que cada parte de um programa está fazendo.

      Dependendo do objetivo do seu programa, os comentários podem servir como notas para si mesmo ou lembretes, ou podem ser escritos com a intenção de fazer com que outros programadores entendam o que o seu código está fazendo.

      De um modo geral, é uma boa ideia escrever comentários enquanto está escrevendo ou atualizando um programa, uma vez que é fácil esquecer seu processo de pensamento mais tarde. Além disso, os comentários escritos posteriormente podem ser menos úteis no longo prazo.

      Sintaxe do comentário

      Os comentários em Go começam com um conjunto de barras (//) e continuam até o final da linha. Ter um espaço em branco após o conjunto de barras refere-se a uma regra idiomática apenas.

      Geralmente, os comentários terão uma aparência como a deste:

      // This is a comment
      

      Os comentários não são executáveis. Assim, não haverá indicação de um comentário ao se executar um programa. Os comentários existem no código fonte para que os humanos os leiam e não para que os computadores os executem.

      Em um programa “Hello, World”! , um comentário pode se parecer com este:

      hello.go

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          // Print “Hello, World!” to console
          fmt.Println("Hello, World!")
      }
      
      

      Num loop for que itera em uma fatia, os comentários podem se parecer com este:

      sharks.go

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          // Define sharks variable as a slice of strings
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          // For loop that iterates over sharks list and prints each string item
          for _, shark := range sharks {
              fmt.Println(shark)
          }
      }
      

      Os comentários devem ser feitos no mesmo recuo do código sobre qual estiver falando. Ou seja, uma definição de função sem recuo teria um comentário sem recuo e cada nível de recuo seguinte teria comentários alinhados ao código que estivesse sendo comentando.

      Por exemplo, aqui está como a função main foi comentada. Os comentários seguem cada nível de recuo do código:

      color.go

      package main
      
      import "fmt"
      
      const favColor string = "blue"
      
      func main() {
          var guess string
          // Create an input loop
          for {
              // Ask the user to guess my favorite color
              fmt.Println("Guess my favorite color:")
              // Try to read a line of input from the user. Print out the error 0
              if _, err := fmt.Scanln(&guess); err != nil {
                  fmt.Printf("%sn", err)
                  return
              }
              // Did they guess the correct color?
              if favColor == guess {
                  // They guessed it!
                  fmt.Printf("%q is my favorite color!n", favColor)
                  return
              }
              // Wrong! Have them guess again.
              fmt.Printf("Sorry, %q is not my favorite color. Guess again.n", guess)
          }
      }
      

      Os comentários são feitos para ajudar os programadores, seja o programador original ou outra pessoa usando ou colaborando no projeto. Se os comentários não puderem ser mantidos e atualizados corretamente com a base de código, é melhor que não se incluam comentários, em vez de escrever um comentário que contradiga ou vá contradizer o código.

      Ao comentar o código, você deve procurar responder à pergunta por que por trás do código ao invés de o que ou como. A menos que o código seja particularmente complicado, de maneira geral, examinar o código basta para responder o o que ou como, motivo pelo pelo qual os comentários normalmente se concentram no por que.

      Comentários em bloco

      Os comentários em bloco podem ser usados para explicar códigos complicados ou códigos com os quais você não espera que o leitor esteja familiarizado.

      Você pode criar comentários em bloco de duas maneiras em Go. A primeira é usar um conjunto de barras duplas e repeti-las a cada linha.

      // First line of a block comment
      // Second line of a block comment
      

      A segunda é usar identificadores de abertura (/*) e identificadores de encerramento (*/). Para documentar o código, usar sempre a sintaxe de // é considerada como uma decisão idiomática. Você somente usará a sintaxe /* ... */ na depuração, sobre a qual valor falar mair adiante neste artigo.

      /*
      Everything here
      will be considered
      a block comment
      */
      

      Neste exemplo, o comentário em bloco define o que está acontecendo na função MustGet():

      function.go

      // MustGet will retrieve a url and return the body of the page.
      // If Get encounters any errors, it will panic.
      func MustGet(url string) string {
          resp, err := http.Get(url)
          if err != nil {
              panic(err)
          }
      
          // don't forget to close the body
          defer resp.Body.Close()
          var body []byte
          if body, err = ioutil.ReadAll(resp.Body); err != nil {
              panic(err)
          }
          return string(body)
      }
      

      É comum ver comentários em bloco no início das funções exportadas em Go; esses comentários também são o que gera a documentação do seu código. Os comentários em bloco também são usados quando as operações são menos objetivas e, portanto, exigem uma explicação mais detalhada. Com exceção da documentação sobre as funções, evite o excesso de comentários sobre o código e confie em que os demais programadores entenderão a linguagem Go, a menos que você esteja escrevendo para um público em particular.

      Comentários feitos na linha

      Os comentários são feitos na mesma linha de uma instrução, após o código, propriamente dito. Assim como outros comentários, eles começam com um conjunto de barras. Novamente, não é necessário ter um espaço em branco após as barras, mas é considerada uma regra idiomática usá-las.

      Geralmente, os comentários feitos na linha se parecem com este:

      [code]  // Inline comment about the code
      

      Os comentários na linha devem ser usados com moderação, mas podem ser eficazes para explicar partes do código complicadas ou não óbvias. Eles também podem ser úteis se você achar que, no futuro, poderá não se lembrar de uma linha do código que está escrevendo, ou se estiver colaborando com alguém que você sabe que talvez não esteja familiarizado com todos os aspectos do código.

      Por exemplo, caso não use muita matemática nos seus programas em Go, você ou seus colaboradores podem não saber que o seguinte cria um número complexo, então você pode querer incluir um comentário na linha sobre isso:

      z := x % 2  // Get the modulus of x
      

      Também é possível usar comentários na linha para explicar a razão para estar fazendo algo, ou fornecer algumas informações extras, como em:

      x := 8  // Initialize x with an arbitrary number
      

      Você somente deve usar os comentários na linha quando necessário e quando eles puderem proporcionar orientações úteis para a pessoa que lê o programa.

      Comentando o código para fins de teste

      Além de usar comentários como uma maneira de documentar o código, também é possível usar sinalizadores de abertura (/*) e sinalizadores de encerramento (*/) para criar um comentário em bloco. Isso permite que você faça um comentário sobre o código, dizendo que não deseja executar enquanto estiver testando ou depurando um programa que estiver criando no momento. Ou seja, quando aparecerem erros após implementar novas linhas do código, você pode querer fazer comentários em algumas delas para ver se pode resolver esse problema específico.

      Usar os sinalizadores /* e */ também pode permitir que você tente alternativas enquanto estiver determinando como configurar o seu código. Também é possível usar blocos de comentários para fazer comentários sobre um código que estiver apresentando falhas, enquanto você continua a trabalhar em outras partes do seu código.

      multiply.go

      // Function to add two numbers
      func addTwoNumbers(x, y int) int {
          sum := x + y
          return sum
      }
      
      // Function to multiply two numbers
      func multiplyTwoNumbers(x, y int) int {
          product := x * y
          return product
      }
      
      func main() {
          /*
              In this example, we're commenting out the addTwoNumbers
              function because it is failing, therefore preventing it from executing.
              Only the multiplyTwoNumbers function will run
      
              a := addTwoNumbers(3, 5)
              fmt.Println(a)
      
          */
      
          m := multiplyTwoNumbers(5, 9)
          fmt.Println(m)
      }
      

      Nota: fazer comentários no código é algo que só deve ser feito para fins de teste. Não deixe trechos do código com comentários em seu programa final.

      Fazer comentários no código usando os sinalizadores /* e */ pode permitir que você experimente outros métodos de programação, bem como pode ser útil para que você encontre a fonte de um erro através de comentários feitos sistematicamente e da execução de partes de um programa.

      Conclusão

      Usar comentários dentro dos seus programas em Go ajuda a tornar seus programas mais legíveis para os humanos, inclusive para você mesmo, no futuro. Adicionar comentários apropriados – que sejam relevantes e úteis – pode facilitar que outras pessoas colaborem com você em projetos de programação e pode tornar o valor do seu código mais óbvio.

      Comentar seu código corretamente em Go também permitirá que você use a ferramenta Godoc. Godoc é uma ferramenta que extrairá os comentários do seu código e gerará uma documentação para o seu programa em Go.



      Source link

      Como escrever instruções condicionais em Go


      Introdução

      As instruções condicionais fazem parte de todas as linguagens de programação. Com as instruções condicionais, podemos ter códigos que algumas vezes executam e em outras ocasiões não, dependendo das condições do programa naquele momento.

      Quando executamos totalmente cada instrução de um programa, não estamos pedindo que o programa avalie condições específicas. Ao usar as instruções condicionais, os programas podem determinar se certas condições estão sendo cumpridas e, então, ser informados do que fazer a seguir.

      Vejamos alguns exemplos de onde usaríamos as instruções condicionais:

      • Se o aluno tiver mais de 65% de acertos em seu teste, informar que ele tem nota de aprovação; caso contrário, informar que ele não conseguiu nota para aprovação.
      • Se ele tiver dinheiro em sua conta, calcular os juros; caso não tenha, cobrar uma taxa a título de multa.
      • Se eles comprarem 10 laranjas ou mais, calcular um desconto de 5%; caso eles comprem menos, não calcule.

      Ao avaliar as condições e atribuir o código a ser executado com base em se essas condições são cumpridas ou não, estamos escrevendo códigos condicionais.

      Este tutorial explicará a você sobre como escrever instruções condicionais na linguagem de programação em Go.

      Instruções if

      Começaremos com a instrução if, que avaliará se uma instrução é verdadeira ou falsa e executará o código apenas no caso em que a instrução for verdadeira.

      Num editor de texto simples, abra um arquivo e escreva o seguinte código:

      grade.go

      package main
      
      import "fmt"
      
      func main() {
          grade := 70
      
          if grade >= 65 {
              fmt.Println("Passing grade")
          }
      }
      

      Com esse código, temos a grade variável e estamos dando a ela o valor inteiro de 70. Em seguida, estamos usando a instrução if para avaliar se a nota variável é ou não maior ou igual (>=) a 65. Se ela atender a essa condição, estamos dizendo ao programa para imprimir a string Passing grade.

      Salve o programa como grade.go e o execute em um ambiente de programação local a partir de uma janela de terminal com o comando go run grade.go.

      Neste caso, a nota de 70 realmente atende à condição de ser maior ou igual a 65, de modo que você receberá o seguinte resultado assim que executar o programa:

      Output

      Passing grade

      Agora, vamos alterar o resultado deste programa, mudando o valor da variável grade para 60:

      grade.go

      package main
      
      import "fmt"
      
      func main() {
          grade := 60
      
          if grade >= 65 {
              fmt.Println("Passing grade")
          }
      }
      

      Ao salvarmos e executarmos este código, não iremos receber nenhum resultado porque a condição não foi cumprida e não dissemos ao programa para executar outra instrução.

      Para dar mais um exemplo, vamos calcular se um saldo de conta bancária está abaixo de 0. Vamos criar um arquivo chamado account.go e escrever o seguinte programa:

      account.go

      package main
      
      import "fmt"
      
      func main() {
          balance := -5
      
          if balance < 0 {
              fmt.Println("Balance is below 0, add funds now or you will be charged a penalty.")
          }
      }
      

      Quando executarmos o programa com o go run account.go, receberemos o seguinte resultado:

      Output

      Balance is below 0, add funds now or you will be charged a penalty.

      No programa, nós inicializamos a variável balance com o valor de -5, que é menor que 0. Como o saldo cumpriu a condição da instrução if (balance < 0), assim que salvarmos e executarmos o código, receberemos o resultado da string. Novamente, se alterarmos o saldo para 0 ou um número positivo, não iremos receber nenhum resultado.

      Instruções else

      É provável que queiramos que o programa faça algo mesmo quando uma instrução if avalia algo como falso. No nosso exemplo de nota, queremos produzir o resultado de se a nota é de aprovação ou desaprovação.

      Para fazer isso, adicionaremos uma instrução else na condição da nota acima que é construída dessa forma:

      grade.go

      package main
      
      import "fmt"
      
      func main() {
          grade := 60
      
          if grade >= 65 {
              fmt.Println("Passing grade")
          } else {
              fmt.Println("Failing grade")
          }
      }
      

      Como a variável de nota tem o valor de 60, a instrução if a avalia como falsa, então o programa não irá imprimir Passing grade. A instrução else que segue diz ao programa para fazer algo, de qualquer maneira.

      Quando salvarmos e executarmos o programa, receberemos o seguinte resultado:

      Output

      Failing grade

      Se reescrevermos o programa para dar à nota um valor de 65 ou mais, em vez disso, receberemos o resultado Passing grade.

      Para adicionar instrução else ao exemplo da conta bancária, reescrevemos o código desta forma:

      account.go

      package main
      
      import "fmt"
      
      func main() {
          balance := 522
      
          if balance < 0 {
              fmt.Println("Balance is below 0, add funds now or you will be charged a penalty.")
          } else {
              fmt.Println("Your balance is 0 or above.")
          }
      }
      

      Output

      Your balance is 0 or above.

      Aqui, mudamos o valor da variável balance para um número positivo, de maneira que a instrução else seja impressa. Para fazer com que a primeira instrução if seja impressa, podemos reescrever o valor para um número negativo.

      Ao combinar uma instrução if com uma instrução else, você estará construindo uma instrução condicional de duas partes que irá dizer ao computador para executar certos códigos se a condição if for cumprida.

      Instruções else if

      Até agora, apresentamos uma opção Booleana para as instruções condicionais, com cada instrução if avaliando como verdadeiro ou falso. Em muitos casos, vamos querer um programa que avalie mais de dois resultados possíveis. Para fazer isso, usaremos uma instrução Senão se, que é escrita em Go como else if. A else if, ou instrução “Senão se” é parecida com a instrução if e avaliará outra condição.

      No programa da conta bancária, podemos querer ter três saídas distintas para obter três situações diferentes:

      • O saldo está abaixo de 0
      • O saldo é igual a 0
      • O saldo está acima de 0

      A instrução else if será colocada entre a instrução if e a instrução else do seguinte modo:

      account.go

      package main
      
      import "fmt"
      
      func main() {
          balance := 522
      
          if balance < 0 {
              fmt.Println("Balance is below 0, add funds now or you will be charged a penalty.")
          } else if balance == 0 {
              fmt.Println("Balance is equal to 0, add funds soon.")
          } else {
              fmt.Println("Your balance is 0 or above.")
          }
      }
      

      Agora, há três possíveis resultados que podem ocorrer assim que executarmos o programa:

      • Se a variável balance for igual a 0, receberemos o resultado da instrução else if (Balance is equal to 0, add funds soon.) (Saldo igual a 0, adicione fundos logo.).
      • Se a variável balance for definida em um número positivo, receberemos o resultado da instrução else (Your balance is 0 or above.) (Seu saldo é 0 ou mais).
      • Se a variável balance for definida em um número negativo, o resultado será a string da instrução if (Balance is below 0, add funds now or you will be charged a penalty) (Saldo abaixo de 0, adicione fundos agora ou haverá cobrança de uma multa).

      Mas e se, apesar disso, quisermos ter mais de três possibilidades? Podemos fazer isso escrevendo mais de um instrução else if no nosso código.

      No programa grade.go, vamos reescrever o código para que haja algumas notas alfabéticas que correspondam a intervalos de notas numéricas:

      • 90 ou acima equivale a uma nota A
      • 80-89 equivale a uma nota B
      • 70-79 equivale a uma nota C
      • 65-69 equivale a uma nota D
      • 64 ou abaixo equivale a uma nota F

      Para executar esse código, precisaremos de uma instrução if, três instruções else if e uma instrução else que lidará com todos os casos de desaprovação.

      Vamos reescrever o código do exemplo anterior para ter strings que imprimam cada uma das avaliações alfabéticas. Podemos manter nossa instrução else da mesma forma.

      grade.go

      package main
      
      import "fmt"
      
      func main() {
          grade := 60
      
          if grade >= 90 {
              fmt.Println("A grade")
          } else if grade >= 80 {
              fmt.Println("B grade")
          } else if grade >= 70 {
              fmt.Println("C grade")
          } else if grade >= 65 {
              fmt.Println("D grade")
          } else {
              fmt.Println("Failing grade")
          }
      }
      

      Como as instruções else if avaliarão em ordem, podemos manter nossas instruções bastante básicas. Este programa está completando os seguintes passos:

      1. Se a nota for maior que 90, o programa irá imprimir A grade, se a nota for menor que 90, o programa continuará com a próxima instrução…

      2. Se a nota for maior ou igual a 80, o programa irá imprimir B grade, se a nota for 79 ou menos, o programa continuará com a próxima instrução…

      3. Se a nota for maior ou igual a 70, o programa irá imprimir C grade, se a nota for 69 ou menos, o programa continuará com a próxima instrução…

      4. Se a nota for maior ou igual a 65, o programa irá imprimir D grade, se a nota for 64 ou menos, o programa continuará com a próxima instrução…

      5. O programa irá imprimir Failing grade porque todas as condições acima não foram cumpridas.

      Instruções if aninhadas

      Assim que estiver se sentindo confortável com as instruções if, else if e else, siga para as instruções condicionais aninhadas. Podemos usar as instruções if aninhadas para situações onde queremos verificar uma condição secundária caso a primeira condição execute como verdadeira. Para fazer isso, podemos ter uma instrução if-else dentro de outra instrução if-else. Vejamos a sintaxe de uma instrução if aninhada:

      if statement1 { // outer if statement
          fmt.Println("true")
      
          if nested_statement { // nested if statement
              fmt.Println("yes")
          } else { // nested else statement
              fmt.Println("no")
          }
      
      } else { // outer else statement
          fmt.Println("false")
      }
      

      Alguns possíveis resultados podem resultar deste código:

      • Se a instrução statement1 é avaliada como verdadeira, o programa irá avaliar se a nested_statement também é avaliada como verdadeira. Se ambos os casos forem verdadeiros, o resultado será:

      Output

      true yes
      • Se, porém, a statement1 for avaliada como verdadeira, mas a nested_statement for avaliada como falsa, então o resultado será:

      Output

      true no
      • E,caso a statement1 for avaliada como falsa, a instrução if-else aninhada não será executada, de modo que a instrução else será executada sozinha e o resultado será:

      Output

      false

      Também podemos ter várias instruções if aninhadas ao longo do nosso código:

      if statement1 { // outer if
          fmt.Println("hello world")
      
          if nested_statement1 { // first nested if
              fmt.Println("yes")
      
          } else if nested_statement2 { // first nested else if
              fmt.Println("maybe")
      
          } else { // first nested else
              fmt.Println("no")
          }
      
      } else if statement2 { // outer else if
          fmt.Println("hello galaxy")
      
          if nested_statement3 { // second nested if
              fmt.Println("yes")
          } else if nested_statement4 { // second nested else if
              fmt.Println("maybe")
          } else { // second nested else
              fmt.Println("no")
          }
      
      } else { // outer else
          statement("hello universe")
      }
      

      Neste código, há uma instrução if aninhada dentro de cada instrução if, além da instrução else if. Isso permitirá mais opções dentro de cada condição.

      Vamos examinar um exemplo de instruções if aninhadas com nosso programa grade.go. Podemos verificar primeiro se uma nota é de aprovação (maior ou igual a 65%) e, então, avaliar a qual nota alfabética a nota numérica deve equivaler. No entanto, se a nota não for de aprovação, não precisaremos executar pela avaliação alfabética. Em vez disso, poderemos ter o relatório do programa de que a avaliação foi de desaprovação. Nosso código modificado com a instrução if aninhada se parecerá com este:

      grade.go

      
      package main
      
      import "fmt"
      
      func main() {
          grade := 92
          if grade >= 65 {
              fmt.Print("Passing grade of: ")
      
              if grade >= 90 {
                  fmt.Println("A")
      
              } else if grade >= 80 {
                  fmt.Println("B")
      
              } else if grade >= 70 {
                  fmt.Println("C")
      
              } else if grade >= 65 {
                  fmt.Println("D")
              }
      
          } else {
              fmt.Println("Failing grade")
          }
      }
      

      Se executarmos o código com a variável grade definida como o valor de númer o inteiro 92, a primeira condição será cumprida e o programa irá imprimir Passing grade of: . Em seguida, ele irá verificar se a nota é maior ou igual a 90 e, como essa condição também é cumprida, irá imprimir A.

      Se executarmos o código com a variável grade definida em 60, significa que a primeira condição não foi cumprida e, assim, o programa irá ignorar as instruções if aninhadas e prosseguirá com a instrução else e o programa imprimirá Failing grade.

      É claro que podemos adicionar ainda mais opções a isso e usar uma segunda camada de instruções if aninhadas. Talvez queiramos avaliar em relação às notas de A+, A e A- separadamente. Podemos fazer isso primeiro verificando se a nota é de aprovação; depois, verificando para saber se a nota é 90 ou acima e, em seguida, verificando se a nota está acima de 96 em relação a uma avaliação de A+:

      grade.go

      ...
      if grade >= 65 {
          fmt.Print("Passing grade of: ")
      
          if grade >= 90 {
              if grade > 96 {
                  fmt.Println("A+")
      
              } else if grade > 93 && grade <= 96 {
                  fmt.Println("A")
      
              } else {
                  fmt.Println("A-")
              }
      ...
      

      Neste código, para uma variável grade definida em 96, o programa irá executar o seguinte:

      1. Verificar se a nota é maior ou igual a 65 (verdadeiro)
      2. Imprimir Passing grade of:
      3. Verificar se a nota é maior ou igual a 90 (verdadeiro)
      4. Verificar se a nota é maior que 96 (falso)
      5. Verificar se a nota é maior que 93 e também menor ou igual a 96 (verdadeiro)
      6. Imprimir A
      7. Saia dessas instruções condicionais aninhadas e continue com o código restante

      Portanto, o resultado do programa para uma nota 96 se parece com este:

      Output

      Passing grade of: A

      As instruções if aninhadas podem dar a oportunidade de adicionar diversos níveis específicos de condições ao seu código.

      Conclusão

      Ao usar instruções condicionais como a instrução if, você terá maior controle sobre o que seu programa executa. As instruções condicionais dizem ao programa para avaliar se uma certa condição está sendo cumprida. Se a condição for cumprida, o programa irá executar o código específico; mas, se não for cumprida, o programa continuará passando para outro código.

      Para continuar praticando instruções condicionais, tente usar operadores diferentes para adquirir maior familiaridade com as instruções condicionais.



      Source link