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. setTimeout
precisa 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
à second
funçã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)
}
setTimeout
leva 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.log
em uma função anônima e a passou para setTimeout
, em seguida, definiu a função para ser executada após 0
milissegundos.
Agora chame as funções, como você fez antes:
// Execute the functions
first()
second()
third()
Você pode esperar com um setTimeout
conjunto para 0
que 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.log
chamada 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
A 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 osfirst()
logs1
para o console, removafirst()
da pilha. - Adicione
second()
à pilha, execute ossecond()
logs2
para o console, removasecond()
da pilha. - Adicione
third()
à pilha, execute osthird()
logs3
para o console, removathird()
da pilha.
O segundo exemplo com setTimout
fica assim:
- Adicione
first()
à pilha, execute osfirst()
logs1
para o console, removafirst()
da pilha. - Adicione
second()
à pilha, corrasecond()
.- Adicione
setTimeout()
à pilha, execute asetTimeout()
API da Web que inicia um cronômetro e adiciona a função anônima à fila , removasetTimeout()
da pilha.
- Adicione
- Remova
second()
da pilha. - Adicione
third()
à pilha, execute osthird()
logs3
para o console, removathird()
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 registra2
no 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
A 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 setTimeout
exemplo, 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 0
segundos. É importante lembrar que o cronômetro não significa que o código será executado em exatamente 0
segundos 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 setTimeout
exemplo, 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 third
funçã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 higherOrderFunction
que recebe uma função callback
como um argumento e a passa fn
como 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 first
, second
e third
funçõ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 third
função sempre atrase a execução até que a ação assíncrona na second
função seja concluída. É aqui que entram os retornos de chamada. Em vez de executar first
, second
e third
no nível superior de execução, você passará a third
função como um argumento para second
. A second
funçã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 first
e second
, em seguida, passe third
como 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 1
será impresso, e depois da conclusão do temporizador (neste caso, zero segundos, mas você pode alterá-lo para qualquer quantidade) ele irá imprimir 2
depois 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 response
e um possível error
, tornando a função callbackHell
visualmente 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 Promise
sintaxe e deve inicializá-la com uma função. A função que é passada para uma promessa tem parâmetros resolve
e reject
. As funções resolve
e reject
tratam 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 pending
status e undefined
valor:
__proto__: Promise
[[PromiseStatus]]: "pending"
[[PromiseValue]]: undefined
Até agora, nada foi estabelecido para a promessa, então ela ficará lá em um pending
estado 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 fulfilled
e um value
valor 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 value
vai de undefined
a 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 then
que será executado depois que uma promessa chegar resolve
ao código. then
retornará o valor da promessa como um parâmetro.
É assim que você retornaria e registraria o value
da 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 then
sintaxe garante que o response
será registrado apenas quando a setTimeout
operação for concluída após 2000
milissegundos. 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 then
pode 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 then
registrará o valor de retorno:
Resolving an asynchronous request! And chaining!
Como then
pode 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 fulfilled
estado. 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 getUsers
funçã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 onSuccess
for 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 catch
método de instância. Isso fornecerá um retorno de chamada de falha com o error
como parâmetro.
Execute o getUser
comando com onSuccess
definido como false
, usando o then
método para o caso de sucesso e o catch
mé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 then
será ignorado e catch
tratará o erro:
Failed to fetch data!
Se você mudar o sinalizador e resolve
, em vez disso, o catch
será 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 Promise
objetos:
Método | Descrição |
---|---|
then() | Alças a resolve . Retorna uma promessa e chama a onFulfilled função de forma assíncrona |
catch() | Alças a reject . Retorna uma promessa e chama a onRejected função de forma assíncrona |
finally() | Chamado quando uma promessa é cumprida. Retorna uma promessa e chama a onFinally funçã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)
})
A fetch
solicitação é enviada ao https://api.github.com/users/octocat
URL, que espera de forma assíncrona por uma resposta. O primeiro then
passa a resposta para uma função anônima que formata a resposta como dados JSON e , em seguida, passa o JSON para uma segunda then
que registra os dados no console. A catch
instruçã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 then
para 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 async
funções e a await
palavra-chave para facilitar o trabalho com promessas.
Funções assíncronas com async/await
Uma async
função permite que você trate o código assíncrono de uma maneira que parece síncrona. async
funçõ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 async
função adicionando a async
palavra – 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 getUser
função:
console.log(getUser())
Isso dará o seguinte:
__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: Object
Isso significa que você pode lidar com uma async
função then
da mesma forma que faria com uma promessa. Experimente com o seguinte código:
getUser().then((response) => console.log(response))
Essa chamada para getUser
passa 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 async
função pode manipular uma promessa chamada dentro dela usando o await
operador. await
pode ser usado dentro de uma async
funçã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 await
seguinte 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 await
operadores aqui garantem que o data
não seja registrado antes de a solicitação preenchê-lo com dados.
Agora o final data
pode ser feito dentro da getUser
funçã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 usarawait
– no entanto, algumas novas versões de navegadores e Node permitem o uso de nível superiorawait
, o que permite que você ignore a criação de uma função assíncrona para envolver oawait
.
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 catch
mé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 catch
bloco se receber um erro e registrará esse erro no console.
O código JavaScript assíncrono moderno é mais frequentemente tratado com async
/ await
sintaxe, 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 async
/ await
, como combinar promessas com Promise.all()
.
Nota:
async
/await
pode 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 async
/ await
sintaxe. Finalmente, você usou a API Fetch Web para lidar com ações assíncronas.