Aguarde...

19 de setembro de 2020

Noções básicas sobre o loop de eventos, retornos de chamada, promessas e assíncrono / aguardar em JavaScript

Noções básicas sobre o loop de eventos, retornos de chamada, promessas e assíncrono / aguardar em JavaScript

Introdução

Nos primórdios da Internet, os sites geralmente consistiam em dados estáticos em uma página HTML . Mas agora que os aplicativos da web se tornaram mais interativos e dinâmicos, tornou-se cada vez mais necessário fazer operações intensivas, como fazer solicitações de rede externa para recuperar dados da API . Para lidar com essas operações em JavaScript, um desenvolvedor deve usar técnicas de programação assíncrona .

Como o JavaScript é uma linguagem de programação de thread único com um modelo de execução síncrona que processa uma operação após a outra, ele só pode processar uma instrução por vez. No entanto, uma ação como solicitar dados de uma API pode levar um período de tempo indeterminado, dependendo do tamanho dos dados solicitados, da velocidade da conexão de rede e de outros fatores. Se as chamadas de API fossem realizadas de maneira síncrona, o navegador não seria capaz de lidar com nenhuma entrada do usuário, como rolar ou clicar em um botão, até que a operação fosse concluída. Isso é conhecido como bloqueio .

Para evitar o comportamento de bloqueio, o ambiente do navegador tem muitas APIs da Web que o JavaScript pode acessar que são assíncronas , o que significa que podem ser executadas em paralelo com outras operações em vez de sequencialmente. Isso é útil porque permite que o usuário continue usando o navegador normalmente enquanto as operações assíncronas estão sendo processadas.

Como desenvolvedor de JavaScript, você precisa saber como trabalhar com APIs da Web assíncronas e lidar com a resposta ou o erro dessas operações. Neste artigo, você aprenderá sobre o loop de eventos, a maneira original de lidar com o comportamento assíncrono por meio de retornos de chamada, a adição atualizada de promessas do ECMAScript 2015 e a prática moderna de uso async/await.

Observação : este artigo enfoca o JavaScript do lado do cliente no ambiente do navegador. Os mesmos conceitos são geralmente verdadeiros no ambiente Node.js , no entanto, Node.js usa suas próprias APIs C ++ em oposição às APIs da Web do navegador . Para mais informações sobre a programação assíncrona no Node.js, veja como escrever código assíncrono em Node.js .

O Loop de Eventos

Esta seção explicará como o JavaScript trata o código assíncrono com o loop de eventos. Primeiro, ele passará por uma demonstração do loop de eventos em funcionamento e, em seguida, explicará os dois elementos do loop de eventos: a pilha e a fila.

O código JavaScript que não usa APIs da Web assíncronas será executado de maneira síncrona – um de cada vez, sequencialmente. Isso é demonstrado por este código de exemplo que chama três funções em que cada uma imprime um número no console :

// Define three example functions
function first() {
  console.log(1)
}

function second() {
  console.log(2)
}

function third() {
  console.log(3)
}

Neste código, você define três funções que imprimem números com console.log().

Em seguida, escreva chamadas para as funções:

// Execute the functions
first()
second()
third()

A saída será baseada na ordem das funções foram chamados: first()second()e, em seguida third().

1
2
3

Quando uma API da Web assíncrona é usada, as regras se tornam mais complicadas. Uma API integrada com a qual você pode testar isso é setTimeout, que define um cronômetro e executa uma ação após um determinado período de tempo. setTimeoutprecisa ser assíncrono, caso contrário, todo o navegador permaneceria congelado durante a espera, o que resultaria em uma experiência do usuário ruim.

Adicione setTimeoutà secondfunção para simular uma solicitação assíncrona:

// Define three example functions, but one of them contains asynchronous code
function first() {
  console.log(1)
}

function second() {
  setTimeout(() => {
    console.log(2)
  }, 0)
}

function third() {
  console.log(3)
}

setTimeoutleva dois argumentos: a função que será executada de forma assíncrona e a quantidade de tempo que ela aguardará antes de chamar essa função. Neste código, você envolveu console.logem uma função anônima e a passou para setTimeout, em seguida, definiu a função para ser executada após 0milissegundos.

Agora chame as funções, como você fez antes:

// Execute the functions
first()
second()
third()

Você pode esperar com um setTimeoutconjunto para 0que a execução dessas três funções ainda resulte na impressão dos números em ordem sequencial. Mas por ser assíncrona, a função com o tempo limite será impressa por último:

1
3
2

Se você definir o tempo limite para zero segundos ou cinco minutos, não fará diferença – a console.logchamada pelo código assíncrono será executada após as funções síncronas de nível superior. Isso acontece porque o ambiente de host JavaScript, neste caso o navegador, usa um conceito denominado loop de eventos para lidar com a simultaneidade, ou eventos paralelos. Como o JavaScript só pode executar uma instrução por vez, ele precisa que o loop de eventos seja informado de quando executar cada instrução específica. O loop de eventos lida com isso com os conceitos de pilha e fila .

Pilha

pilha , ou pilha de chamadas, mantém o estado de qual função está em execução no momento. Se você não está familiarizado com o conceito de pilha, pode imaginá-lo como um array com as propriedades “Último a entrar, primeiro a sair” (LIFO), o que significa que você só pode adicionar ou remover itens do final da pilha. O JavaScript executará o quadro atual (ou chamada de função em um ambiente específico) na pilha, então o removerá e seguirá para o próximo.

Para o exemplo que contém apenas o código síncrono, o navegador lida com a execução na seguinte ordem:

  • Adicione first()à pilha, execute os first()logs 1para o console, remova first()da pilha.
  • Adicione second()à pilha, execute os second()logs 2para o console, remova second()da pilha.
  • Adicione third()à pilha, execute os third()logs 3para o console, remova third()da pilha.

O segundo exemplo com setTimoutfica assim:

  • Adicione first()à pilha, execute os first()logs 1para o console, remova first()da pilha.
  • Adicione second()à pilha, corra second().
    • Adicione setTimeout()à pilha, execute a setTimeout()API da Web que inicia um cronômetro e adiciona a função anônima à fila , remova setTimeout()da pilha.
  • Remova second()da pilha.
  • Adicione third()à pilha, execute os third()logs 3para o console, remova third()da pilha.
  • O loop de eventos verifica se há mensagens pendentes na fila e encontra a função anônima setTimeout(), adiciona a função à pilha que registra 2no console e a remove da pilha.

Usando setTimeout, uma API da Web assíncrona, introduz o conceito de fila , que este tutorial abordará a seguir.

Fila

fila , também conhecida como fila de mensagens ou fila de tarefas, é uma área de espera para funções. Sempre que a pilha de chamadas estiver vazia, o loop de eventos verificará se há mensagens em espera na fila, começando pela mensagem mais antiga. Assim que encontrar um, ele o adicionará à pilha, que executará a função na mensagem.

No setTimeoutexemplo, a função anônima é executada imediatamente após o restante da execução de nível superior, pois o cronômetro foi definido como 0segundos. É importante lembrar que o cronômetro não significa que o código será executado em exatamente 0segundos ou qualquer que seja o tempo especificado, mas que adicionará a função anônima à fila nesse período de tempo. Este sistema de fila existe porque se o cronômetro adicionar a função anônima diretamente à pilha quando o cronômetro terminar, ele interromperá qualquer função que estiver em execução no momento, o que pode ter efeitos indesejados e imprevisíveis.

Nota: Há também outra fila chamada fila de trabalho ou fila de microtarefa que lida com promessas. Microtarefas como promessas são tratadas com uma prioridade mais alta do que macrotarefas como setTimeout.

Agora você sabe como o loop de eventos usa a pilha e a fila para lidar com a ordem de execução do código. A próxima tarefa é descobrir como controlar a ordem de execução em seu código. Para fazer isso, primeiro você aprenderá sobre a maneira original de garantir que o código assíncrono seja tratado corretamente pelo loop de eventos: funções de retorno de chamada.

Funções de retorno de chamada

No setTimeoutexemplo, a função com o tempo limite foi executada depois de tudo no contexto de execução de nível superior principal. Mas se você quisesse garantir que uma das funções, como a thirdfunção, fosse executada após o tempo limite, seria necessário usar métodos de codificação assíncronos. O tempo limite aqui pode representar uma chamada de API assíncrona que contém dados. Você deseja trabalhar com os dados da chamada de API, mas deve certificar-se de que os dados sejam retornados primeiro.

A solução original para lidar com esse problema é usar funções de retorno de chamada . As funções de retorno de chamada não têm sintaxe especial; eles são apenas uma função que foi passada como um argumento para outra função. A função que recebe outra função como argumento é chamada de função de ordem superior . De acordo com essa definição, qualquer função pode se tornar uma função de retorno de chamada se for passada como um argumento. Os retornos de chamada não são assíncronos por natureza, mas podem ser usados ​​para fins assíncronos.

Aqui está um exemplo de código sintático de uma função de ordem superior e um retorno de chamada:

// A function
function fn() {
  console.log('Just a function')
}

// A function that takes another function as an argument
function higherOrderFunction(callback) {
  // When you call a function that is passed as an argument, it is referred to as a callback
  callback()
}

// Passing a function
higherOrderFunction(fn)

Neste código, você define uma função fn, define uma função higherOrderFunctionque recebe uma função callbackcomo um argumento e a passa fncomo um retorno de chamada para higherOrderFunction.

A execução deste código fornecerá o seguinte:

Just a function

Deixe-nos ir de volta para o firstsecondthirdfunções com setTimeout. Isso é o que você tem até agora:

function first() {
  console.log(1)
}

function second() {
  setTimeout(() => {
    console.log(2)
  }, 0)
}

function third() {
  console.log(3)
}

A tarefa é fazer com que a thirdfunção sempre atrase a execução até que a ação assíncrona na secondfunção seja concluída. É aqui que entram os retornos de chamada. Em vez de executar firstsecondthirdno nível superior de execução, você passará a thirdfunção como um argumento para second. A secondfunção executará o retorno de chamada após a conclusão da ação assíncrona.

Aqui estão as três funções com um retorno de chamada aplicado:

// Define three functions
function first() {
  console.log(1)
}

function second(callback) {  setTimeout(() => {
    console.log(2)

    // Execute the callback function
    callback()  }, 0)
}

function third() {
  console.log(3)
}

Agora, execute firstsecond, em seguida, passe thirdcomo um argumento para second:

first()
second(third)

Depois de executar este bloco de código, você receberá a seguinte saída:

1
2
3

Primeiro 1será impresso, e depois da conclusão do temporizador (neste caso, zero segundos, mas você pode alterá-lo para qualquer quantidade) ele irá imprimir 2depois 3. Ao passar uma função como retorno de chamada, você atrasou com êxito a execução da função até que a API da Web assíncrona ( setTimeout) seja concluída.

A principal conclusão aqui é que as funções de retorno de chamada não são assíncronas – setTimeouté a API da Web assíncrona responsável por lidar com tarefas assíncronas. O retorno de chamada apenas permite que você seja informado quando uma tarefa assíncrona for concluída e lida com o sucesso ou falha da tarefa.

Agora que você aprendeu como usar callbacks para lidar com tarefas assíncronas, a próxima seção explica os problemas de aninhar muitos callbacks e criar uma “pirâmide da desgraça”.

Callbacks aninhados e a pirâmide da destruição

As funções de retorno de chamada são uma forma eficaz de garantir a execução atrasada de uma função até que outra seja concluída e retorne com dados. No entanto, devido à natureza aninhada dos retornos de chamada, o código pode ficar confuso se você tiver muitas solicitações assíncronas consecutivas que dependem umas das outras. Isso foi uma grande frustração para os desenvolvedores de JavaScript no início e, como resultado, o código que contém callbacks aninhados costuma ser chamado de “pirâmide da desgraça” ou “inferno de callback”.

Aqui está uma demonstração de callbacks aninhados:

function pyramidOfDoom() {
  setTimeout(() => {
    console.log(1)
    setTimeout(() => {
      console.log(2)
      setTimeout(() => {
        console.log(3)
      }, 500)
    }, 2000)
  }, 1000)
}

Neste código, cada novo setTimeouté aninhado dentro de uma função de ordem superior, criando uma forma de pirâmide de callbacks cada vez mais profundos. A execução desse código forneceria o seguinte:

1
2
3

Na prática, com o código assíncrono do mundo real, isso pode ficar muito mais complicado. Provavelmente, você precisará fazer o tratamento de erros em código assíncrono e, em seguida, passar alguns dados de cada resposta para a próxima solicitação. Fazer isso com retornos de chamada tornará seu código difícil de ler e manter.

Aqui está um exemplo executável de uma “pirâmide da desgraça” mais realista com a qual você pode brincar:

// Example asynchronous function
function asynchronousRequest(args, callback) {
  // Throw an error if no arguments are passed
  if (!args) {
    return callback(new Error('Whoa! Something went wrong.'))
  } else {
    return setTimeout(
      // Just adding in a random number so it seems like the contrived asynchronous function
      // returned different data
      () => callback(null, {body: args + ' ' + Math.floor(Math.random() * 10)}),
      500,
    )
  }
}

// Nested asynchronous requests
function callbackHell() {
  asynchronousRequest('First', function first(error, response) {
    if (error) {
      console.log(error)
      return
    }
    console.log(response.body)
    asynchronousRequest('Second', function second(error, response) {
      if (error) {
        console.log(error)
        return
      }
      console.log(response.body)
      asynchronousRequest(null, function third(error, response) {
        if (error) {
          console.log(error)
          return
        }
        console.log(response.body)
      })
    })
  })
}

// Execute
callbackHell()

Nesse código, você deve fazer com que cada função considere um possível responsee um possível error, tornando a função callbackHellvisualmente confusa.

Executar este código fornecerá o seguinte:

First 9
Second 3
Error: Whoa! Something went wrong.
    at asynchronousRequest (<anonymous>:4:21)
    at second (<anonymous>:29:7)
    at <anonymous>:9:13

Essa forma de lidar com o código assíncrono é difícil de seguir. Como resultado, o conceito de promessas foi introduzido no ES6. Este é o foco da próxima seção.

Promessas

Uma promessa representa a conclusão de uma função assíncrona. É um objeto que pode retornar um valor no futuro. Ela cumpre o mesmo objetivo básico de uma função de retorno de chamada, mas com muitos recursos adicionais e uma sintaxe mais legível. Como um desenvolvedor de JavaScript, você provavelmente gastará mais promessas que consomem tempo do que criá-las, já que geralmente são APIs da Web assíncronas que retornam uma promessa para o desenvolvedor consumir. Este tutorial mostrará como fazer ambos.

Criando uma promessa

Você pode inicializar uma promessa com a new Promisesintaxe e deve inicializá-la com uma função. A função que é passada para uma promessa tem parâmetros resolvereject. As funções resolverejecttratam do sucesso e da falha de uma operação, respectivamente.

Escreva a seguinte linha para declarar uma promessa:

// Initialize a promise
const promise = new Promise((resolve, reject) => {})

Se você inspecionar a promessa inicializada neste estado com o console do seu navegador da web, verá que ela tem um pendingstatus e undefinedvalor:

__proto__: Promise
[[PromiseStatus]]: "pending"
[[PromiseValue]]: undefined

Até agora, nada foi estabelecido para a promessa, então ela ficará lá em um pendingestado para sempre. A primeira coisa que você pode fazer para testar uma promessa é cumprir a promessa resolvendo-a com um valor:

const promise = new Promise((resolve, reject) => {
  resolve('We did it!')})

Agora, ao inspecionar a promessa, você descobrirá que ela tem um status de fulfillede um valuevalor definido para o que você passou resolve:

__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: "We did it!"

Conforme declarado no início desta seção, uma promessa é um objeto que pode retornar um valor. Depois de ser preenchido com sucesso, o valuevai de undefineda ser preenchido com dados.

Uma promessa pode ter três estados possíveis: pendente, cumprida e rejeitada.

  • Pendente – estado inicial antes de ser resolvido ou rejeitado
  • Cumprido – operação bem-sucedida, promessa resolvida
  • Rejeitado – operação falhou, promessa rejeitada

Depois de ser cumprida ou rejeitada, uma promessa é cumprida.

Agora que você tem uma ideia de como as promessas são criadas, vamos ver como um desenvolvedor pode consumir essas promessas.

Consumindo uma promessa

A promessa na última seção foi cumprida com um valor, mas você também deseja acessar o valor. As promessas têm um método chamado thenque será executado depois que uma promessa chegar resolveao código. thenretornará o valor da promessa como um parâmetro.

É assim que você retornaria e registraria o valueda promessa de exemplo:

promise.then((response) => {
  console.log(response)
})

A promessa que você criou tinha um [[PromiseValue]]de We did it!. Esse valor é o que será passado para a função anônima como response:

We did it!

Até agora, o exemplo que você criou não envolveu uma API da Web assíncrona – apenas explicou como criar, resolver e consumir uma promessa nativa de JavaScript. Usando setTimeout, você pode testar uma solicitação assíncrona.

O código a seguir simula dados retornados de uma solicitação assíncrona como uma promessa:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Resolving an asynchronous request!'), 2000)
})

// Log the result
promise.then((response) => {
  console.log(response)
})

O uso da thensintaxe garante que o responseserá registrado apenas quando a setTimeoutoperação for concluída após 2000milissegundos. Tudo isso é feito sem aninhamento de retornos de chamada.

Agora, após dois segundos, ele resolverá o valor da promessa e será conectado then:

Resolving an asynchronous request!

As promessas também podem ser encadeadas para transmitir dados a mais de uma operação assíncrona. Se um valor for retornado em then, outro thenpode ser adicionado que irá cumprir com o valor de retorno do anterior then:

// Chain a promise
promise
  .then((firstResponse) => {
    // Return a new value for the next then
    return firstResponse + ' And chaining!'
  })
  .then((secondResponse) => {
    console.log(secondResponse)
  })

A resposta cumprida na segunda thenregistrará o valor de retorno:

Resolving an asynchronous request! And chaining!

Como thenpode ser encadeado, ele permite que o consumo de promessas pareça mais síncrono do que os retornos de chamada, já que não precisam ser aninhados. Isso permitirá um código mais legível que pode ser mantido e verificado com mais facilidade.

Manipulação de erros

Até agora, você apenas lidou com uma promessa com sucesso resolve, o que coloca a promessa em um fulfilledestado. Porém, frequentemente, com uma solicitação assíncrona, você também precisa lidar com um erro – se a API estiver inativa ou uma solicitação malformada ou não autorizada for enviada. Uma promessa deve ser capaz de lidar com os dois casos. Nesta seção, você criará uma função para testar o caso de sucesso e erro de criação e consumo de uma promessa.

Esta getUsersfunção irá passar um sinalizador para uma promessa e retornar a promessa.

function getUsers(onSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // Handle resolve and reject in the asynchronous API
    }, 1000)
  })
}

Configure o código para que, se onSuccessfor true, o tempo limite seja preenchido com alguns dados. Se false, a função rejeitará com um erro.

function getUsers(onSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // Handle resolve and reject in the asynchronous API
      if (onSuccess) {        resolve([          {id: 1, name: 'Jerry'},          {id: 2, name: 'Elaine'},          {id: 3, name: 'George'},        ])      } else {        reject('Failed to fetch data!')      }    }, 1000)  })
}

Para obter o resultado bem-sucedido, você retorna objetos JavaScript que representam dados do usuário de amostra.

Para lidar com o erro, você usará o catchmétodo de instância. Isso fornecerá um retorno de chamada de falha com o errorcomo parâmetro.

Execute o getUsercomando com onSuccessdefinido como false, usando o thenmétodo para o caso de sucesso e o catchmétodo para o erro:

// Run the getUsers function with the false flag to trigger an error
getUsers(false)
  .then((response) => {
    console.log(response)
  })
  .catch((error) => {
    console.error(error)
  })

Uma vez que o erro foi acionado, o thenserá ignorado e catchtratará o erro:

Failed to fetch data!

Se você mudar o sinalizador e resolve, em vez disso, o catchserá ignorado e os dados retornarão.

// Run the getUsers function with the true flag to resolve successfully
getUsers(true)
  .then((response) => {
    console.log(response)
  })
  .catch((error) => {
    console.error(error)
  })

Isso produzirá os dados do usuário:

(3) [{…}, {…}, {…}]
0: {id: 1, name: "Jerry"}
1: {id: 2, name: "Elaine"}
3: {id: 3, name: "George"}

Para referência, aqui está uma tabela com os métodos do manipulador em Promiseobjetos:

MétodoDescrição
then()Alças a resolve. Retorna uma promessa e chama a onFulfilledfunção de forma assíncrona
catch()Alças a reject. Retorna uma promessa e chama a onRejectedfunção de forma assíncrona
finally()Chamado quando uma promessa é cumprida. Retorna uma promessa e chama a onFinallyfunção de forma assíncrona

As promessas podem ser confusas, tanto para novos desenvolvedores quanto para programadores experientes que nunca trabalharam em um ambiente assíncrono antes. No entanto, conforme mencionado, é muito mais comum consumir promessas do que criá-las. Normalmente, a API da Web de um navegador ou biblioteca de terceiros fornecerá a promessa e você só precisará consumi-la.

Na seção de promessa final, este tutorial irá citar um caso de uso comum de uma API da Web que retorna promessas: a API Fetch .

Usando a API Fetch com promessas

Uma das APIs da Web mais úteis e frequentemente usadas que retorna uma promessa é a API Fetch, que permite que você faça uma solicitação de recurso assíncrona em uma rede. fetché um processo de duas partes e, portanto, requer encadeamento then. Este exemplo demonstra como acessar a API GitHub para buscar os dados de um usuário, ao mesmo tempo em que lida com qualquer erro potencial:

// Fetch a user from the GitHub API
fetch('https://api.github.com/users/octocat')
  .then((response) => {
    return response.json()
  })
  .then((data) => {
    console.log(data)
  })
  .catch((error) => {
    console.error(error)
  })

fetchsolicitação é enviada ao https://api.github.com/users/octocatURL, que espera de forma assíncrona por uma resposta. O primeiro thenpassa a resposta para uma função anônima que formata a resposta como dados JSON e , em seguida, passa o JSON para uma segunda thenque registra os dados no console. A catchinstrução registra qualquer erro no console.

Executar este código resultará no seguinte:

login: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...

Estes são os dados solicitados de https://api.github.com/users/octocat, renderizados no formato JSON.

Esta seção do tutorial mostrou que as promessas incorporam muitas melhorias para lidar com o código assíncrono. Mas, embora usar thenpara lidar com ações assíncronas seja mais fácil de seguir do que a pirâmide de retornos de chamada, alguns desenvolvedores ainda preferem um formato síncrono de escrever código assíncrono. Para atender a essa necessidade, ECMAScript 2016 (ES7) introduziu asyncfunções e a awaitpalavra-chave para facilitar o trabalho com promessas.

Funções assíncronas com async/await

Uma asyncfunção permite que você trate o código assíncrono de uma maneira que parece síncrona. asyncfunções ainda usam promessas por baixo do capô, mas têm uma sintaxe JavaScript mais tradicional. Nesta seção, você experimentará exemplos dessa sintaxe.

Você pode criar uma asyncfunção adicionando a asyncpalavra – chave antes de uma função:

// Create an async function
async function getUser() {
  return {}
}

Embora essa função ainda não esteja tratando de nada assíncrono, ela se comporta de maneira diferente de uma função tradicional. Se você executar a função, verá que ela retorna uma promessa com um [[PromiseStatus]]e em [[PromiseValue]]vez de um valor de retorno.

Experimente fazer isso registrando uma chamada para a getUserfunção:

console.log(getUser())

Isso dará o seguinte:

__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: Object

Isso significa que você pode lidar com uma asyncfunção thenda mesma forma que faria com uma promessa. Experimente com o seguinte código:

getUser().then((response) => console.log(response))

Essa chamada para getUserpassa o valor de retorno para uma função anônima que registra o valor no console.

Você receberá o seguinte ao executar este programa:

{}

Uma asyncfunção pode manipular uma promessa chamada dentro dela usando o awaitoperador. awaitpode ser usado dentro de uma asyncfunção e irá esperar até que uma promessa seja estabelecida antes de executar o código designado.

Com esse conhecimento, você pode reescrever a solicitação Fetch da última seção usando async/ da awaitseguinte maneira:

// Handle fetch with async/await
async function getUser() {
  const response = await fetch('https://api.github.com/users/octocat')
  const data = await response.json()

  console.log(data)
}

// Execute async function
getUser()

Os awaitoperadores aqui garantem que o datanão seja registrado antes de a solicitação preenchê-lo com dados.

Agora o final datapode ser feito dentro da getUserfunção, sem necessidade de uso then. Esta é a saída do registro data:

login: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...

Nota : Em muitos ambientes, asyncé necessário usar await– no entanto, algumas novas versões de navegadores e Node permitem o uso de nível superior await, o que permite que você ignore a criação de uma função assíncrona para envolver o await.

Por fim, como você está lidando com a promessa cumprida na função assíncrona, também pode lidar com o erro na função. Em vez de usar o catchmétodo com then, você usará o padrão try/catch para tratar a exceção.

Adicione o seguinte código destacado:

// Handling success and errors with async/await
async function getUser() {
  try {    // Handle success in try    const response = await fetch('https://api.github.com/users/octocat')
    const data = await response.json()

    console.log(data)
  } catch (error) {    // Handle error in catch    console.error(error)  }}

O programa agora pulará para o catchbloco se receber um erro e registrará esse erro no console.

O código JavaScript assíncrono moderno é mais frequentemente tratado com asyncawaitsintaxe, mas é importante ter um conhecimento prático de como as promessas funcionam, especialmente porque as promessas são capazes de recursos adicionais que não podem ser tratados com asyncawait, como combinar promessas com Promise.all().

Nota: async / awaitpode ser reproduzido usando geradores combinados com promessas para adicionar mais flexibilidade ao seu código. Para saber mais, confira nosso tutorial Entendendo Geradores em JavaScript .

Conclusão

Como as APIs da Web geralmente fornecem dados de forma assíncrona, aprender como lidar com o resultado de ações assíncronas é uma parte essencial de ser um desenvolvedor de JavaScript. Neste artigo, você aprendeu como o ambiente do host usa o loop de eventos para lidar com a ordem de execução do código com a pilha e a fila . Você também experimentou exemplos de três maneiras de lidar com o sucesso ou a falha de um evento assíncrono, com retornos de chamada, promessas e asyncawaitsintaxe. Finalmente, você usou a API Fetch Web para lidar com ações assíncronas.

Postado em Blog
Escreva um comentário