Bom dia amigosAs adições relativamente novas do JavaScript são funções assíncronas e a palavra-chave wait. Esses recursos são basicamente açúcar sintático sobre promessas (promessas), facilitando a gravação e a leitura de códigos assíncronos. Eles fazem o código assíncrono parecer síncrono. Este artigo irá ajudá-lo a descobrir o que é o quê.Condições: conhecimento básico de informática, conhecimento dos conceitos básicos de JS, compreensão dos conceitos básicos de código assíncrono e promessas.Objetivo: Compreender como as promessas são feitas e como são usadas.Assíncrono / aguardar noções básicas
O uso de assíncrono / espera tem duas partes.Palavra-chave assíncrona
Primeiro, temos a palavra-chave assíncrona, que colocamos antes da declaração da função para torná-la assíncrona. Uma função assíncrona é uma função que antecipa a capacidade de usar a palavra-chave wait para executar código assíncrono.Tente digitar o seguinte no console do navegador:function hello(){ return 'Hello' }
hello()
A função retornará 'Hello'. Nada incomum, certo?Mas e se a transformarmos em uma função assíncrona? Tente o seguinte:async function hello(){ return 'Hello' }
hello()
Agora, uma chamada de função retorna uma promessa. Esse é um dos recursos das funções assíncronas - elas retornam valores que são garantidos para serem convertidos em promessas.Você também pode criar expressões funcionais assíncronas, assim:let hello = async function(){ return hello() }
hello()
Você também pode usar as funções de seta:let hello = async () => { return 'Hello' }
Todas essas funções fazem a mesma coisa.Para obter o valor de uma promessa concluída, podemos usar o bloco .then ():hello().then((value) => console.log(value))
... ou mesmo assim:hello().then(console.log)
Assim, adicionar a palavra-chave assíncrona faz com que a função retorne uma promessa em vez de um valor. Além disso, ele permite funções síncronas para evitar qualquer sobrecarga associada à execução e ao suporte ao uso de aguardar. Uma simples adição de assíncrono na frente da função permite a otimização automática de código pelo mecanismo JS. Legal!Palavra-chave aguardada
Os benefícios das funções assíncronas tornam-se ainda mais aparentes quando você os combina com a palavra-chave wait. Ele pode ser adicionado antes de qualquer função baseada em promessa para aguardar a conclusão da promessa e retornar o resultado. Depois disso, o próximo bloco de código é executado.Você pode aguardar ao chamar qualquer função que retorne uma promessa, incluindo funções da API da Web.Aqui está um exemplo trivial:async function hello(){
return greeting = await Promise.resolve('Hello')
}
hello().then(alert)
Obviamente, o código acima é inútil, serve apenas como uma demonstração da sintaxe. Vamos seguir em frente e ver um exemplo real.Reescrevendo código em promessas usando async / waitit
Veja o exemplo de busca do artigo anterior:fetch('coffee.jpg')
.then(response => response.blob())
.then(myBlob => {
let objectURL = URL.createObjectURL(myBlob)
let image = document.createElement('img')
image.src = objectURL
document.body.appendChild(image)
})
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message)
})
Você já deve entender o que são promessas e como elas funcionam, mas vamos reescrever esse código usando async / waitit para ver como é simples:async function myFetch(){
let response = await fetch('coffee.jpg')
let myBlob = await response.blob()
let objectURL = URL.createObjectURL(myBlob)
let image = document.createElement('img')
image.src = objectURL
document.body.appendChild(image)
}
myFetch().catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message)
})
Isso torna o código muito mais simples e fácil de entender - sem .then () blocks!O uso da palavra-chave async transforma uma função em promessa, para que possamos usar uma abordagem mista de promessas e aguardar, destacando a segunda parte da função em um bloco separado para aumentar a flexibilidade:async function myFetch(){
let response = await fetch('coffee.jpg')
return await response.blob()
}
myFetch().then((blob) => {
let objectURL = URL.createObjectURL(blob)
let image = document.createElement('image')
image.src = objectURL
document.body.appendChild(image)
}).catch(e => console.log(e))
Você pode reescrever o exemplo ou executar nossa demonstração ao vivo (consulte também o código-fonte ).Mas como isso funciona?
Embrulhamos o código dentro da função e adicionamos a palavra-chave assíncrona antes da palavra-chave da função. Você precisa criar uma função assíncrona para determinar o bloco de código no qual o código assíncrono será executado; aguardar só funciona dentro de funções assíncronas.Mais uma vez: aguardar só funciona em funções assíncronas.Dentro da função myFetch (), o código é muito parecido com a versão prometida, mas com algumas diferenças. Em vez de usar o bloco .then () após cada método baseado em promessa, basta adicionar a palavra-chave wait antes de chamar o método e atribuir um valor à variável. A palavra-chave waitit faz com que o mecanismo JS pause a execução do código em uma determinada linha, permitindo que outro código seja executado até que a função assíncrona retorne um resultado. Uma vez executado, o código continuará sendo executado a partir da próxima linha.Por exemplo:let response = await fetch('coffee.jpg')
O valor retornado pela promessa fetch () é atribuído à variável de resposta quando o valor fornecido se torna disponível, e o analisador para nessa linha até que a promessa seja concluída. Assim que o valor fica disponível, o analisador passa para a próxima linha de código que cria o Blob. Essa linha também chama o método assíncrono baseado em promessa, então aqui também usamos wait. Quando o resultado da operação retorna, retornamos da função myFetch ().Isso significa que, quando chamamos a função myFetch (), ela retorna uma promessa, para que possamos adicionar .then () a ela, dentro da qual lidamos com a exibição da imagem na tela.Você provavelmente pensa “Isso é ótimo!” E você está certo - menos .then () blocos para agrupar o código, tudo parece código síncrono, por isso é intuitivo.Adicionar tratamento de erros
Se você deseja adicionar tratamento de erros, você tem várias opções.Você pode usar a estrutura try ... catch síncrona com async / waitit. Este exemplo é uma versão estendida do código acima:async function myFetch(){
try{
let response = await fetch('coffee.jpg')
let myBlob = await response.blob()
let objectURL = URL.createObjectURL(myBlob)
let image = document.createElement('img')
image.src = objectURL
document.body.appendChild(image)
} catch(e){
console.log(e)
}
}
myFetch()
O bloco catch () {} aceita um objeto de erro, que chamamos de "e"; Agora, podemos enviá-lo para o console. Isso nos permitirá receber uma mensagem sobre onde o erro ocorreu no código.Se você quiser usar a segunda versão do código mostrado acima, você deve simplesmente continuar usando a abordagem híbrida e adicionar o bloco .catch () ao final da chamada .then (), da seguinte maneira:async function myFetch(){
let response = await fecth('coffee.jpg')
return await response.blob()
}
myFetch().then((blob) => {
let objectURL = URL.createObjectURL
let image = document.createElement('img')
image.src = objectURL
document.body.appendChild(image)
}).catch(e => console.log(e))
Isso é possível porque o bloco .catch () captura erros que ocorrem na função assíncrona e na cadeia de promessas. Se você usar o bloco try / catch aqui, não poderá manipular erros que ocorrem quando a função myFetch () é chamada.Você pode encontrar os dois exemplos no GitHub:busca simples-assíncrona-espera-tentativa-captura.html (consulte a fonte )busca simples-assíncrona-espera-promessa-captura.html (consulte a fonte )Esperando Promise.all ()
O assíncrono / espera é baseado em promessas, para que você possa aproveitar ao máximo as últimas. Isso inclui Promise.all () em particular - você pode facilmente adicionar Aguardar Promise.all () para gravar todos os valores retornados de maneira semelhante ao código síncrono. Mais uma vez, pegue o exemplo do artigo anterior . Mantenha uma guia aberta para comparar com o código mostrado abaixo.Com async / waitit (veja a demonstração ao vivo e o código-fonte ), fica assim:async function fetchAndDecode(url, type){
let repsonse = await fetch(url)
let content
if(type === 'blob'){
content = await response.blob()
} else if(type === 'text'){
content = await response.text()
}
return content
}
async function displayContent(){
let coffee = fetchAndDecode('coffee.jpg', 'blob')
let tea = fetchAndDecode('tea.jpg', 'blob')
let description = fetchAndDecode('description.txt', 'text')
let values = await Promise.all([coffee, tea, description])
let objectURL1 = URL.createObjectURL(values[0])
let objectURL2 = URL.createObjectURL(values[1])
let descText = values[2]
let image1 = document.createElement('img')
let image2 = document.createElement('img')
image1.src = objectURL1
image2.src = objectURL2
document.body.appendChild(image1)
document.body.appendChild(image2)
let para = document.createElement('p')
para.textContent = descText
document.body.appendChild(para)
}
displayContent()
.catch(e => console.log(e))
Fizemos facilmente a função fetchAndDecode () assíncrona com algumas alterações. Preste atenção à linha:let values = await Promise.all([coffee, tea, description])
Usando aguardar, obtemos os resultados de três promessas na variável values, de maneira semelhante ao código síncrono. Devemos agrupar toda a função em uma nova função assíncrona, displayContent (). Não conseguimos uma forte redução de código, mas conseguimos extrair a maior parte do código do bloco .then (), que fornece uma simplificação útil e torna o código mais legível.Para lidar com erros, adicionamos um bloco .catch () à nossa chamada para displayContent (); Ele lida com erros de ambas as funções.Lembre-se: você também pode usar o bloco .finally () para obter um relatório sobre a operação - você pode vê-lo em ação em nossa demonstração ao vivo (veja também o código-fonte ).Desvantagens assíncronas / aguardam
Async / waitit tem algumas falhas.O assíncrono / espera faz com que o código pareça síncrono e, de certa forma, faz com que ele se comporte de forma mais síncrona. A palavra-chave wait (espera) bloqueia a execução do código a seguir até que a promessa seja concluída, como acontece em uma operação síncrona. Isso permite que você execute outras tarefas, mas seu próprio código está bloqueado.Isso significa que seu código pode ficar lento devido a um grande número de promessas pendentes, uma após a outra. Cada espera aguardará a conclusão da anterior, enquanto gostaríamos que as promessas fossem cumpridas simultaneamente, como se não estivéssemos usando async / waitit.Há um padrão de design para atenuar esse problema - desativando todos os processos de promessa armazenando objetos Promise em variáveis e aguardando-os. Vamos ver como isso é implementado.Temos dois exemplos à nossa disposição: slow-async-waitit.html (consulte o código-fonte ) e fast-async-waitit.html (consulte o código-fonte ). Ambos os exemplos começam com uma função de promessa que imita uma operação assíncrona usando setTimeout ():function timeoutPromise(interval){
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve('done')
}, interval)
})
}
Em seguida, segue a função assíncrona timeTest (), que espera três chamadas para timeoutPromise ():async function timeTest(){
...
}
Cada uma das três chamadas para timeTest () termina com um registro do tempo que levou para cumprir a promessa e, então, o tempo necessário para concluir toda a operação é registrado:let startTime = Date.now()
timeTest().then(() => {
let finishTime = Date.now()
let timeTaken = finishTime - startTime
alert('Time taken in milliseconds: ' + timeTaken)
})
Em cada caso, a função timeTest () é diferente.Em slow-async-waitit.html, timeTest () fica assim:async function timeTest(){
await timeoutPromise(3000)
await timeoutPromise(3000)
await timeoutPromise(3000)
}
Aqui, esperamos apenas três chamadas para timeoutPromise, cada vez que você definir um atraso de 3 segundos. Cada chamada aguarda a conclusão da anterior - se você executar o primeiro exemplo, verá uma janela modal em cerca de 9 segundos.No fast-async-waitit.html, timeTest () se parece com isso:async function timeTest(){
const timeoutPromise1 = timeoutPromise(3000)
const timeoutPromise2 = timeoutPromise(3000)
const timeoutPromise3 = timeoutPromise(3000)
await timeoutPromise1
await timeoutPromise2
await timeoutPromise3
}
Aqui, salvamos três objetos Promise em variáveis, o que faz com que os processos associados a ele sejam executados simultaneamente.Além disso, esperamos seus resultados - à medida que as promessas começam a ser cumpridas simultaneamente, as promessas também serão concluídas ao mesmo tempo; Quando você executar o segundo exemplo, verá uma janela modal em cerca de 3 segundos!Você deve testar cuidadosamente o código e manter isso em mente enquanto reduz o desempenho.Outro pequeno inconveniente é a necessidade de agrupar as promessas esperadas em uma função assíncrona.Usando async / waitit com classes
Concluindo, observamos que você pode adicionar assíncrono mesmo nos métodos para criar classes, para que eles retornem promessas e esperem promessas dentro delas. Pegue o código do artigo sobre JS orientado a objeto e compare-o com a versão modificada usando async:class Person{
constructor(first, last, age, gender, interests){
this.name = {
first,
last
}
this.age = age
this.gender = gender
this.interests = interests
}
async greeting(){
return await Promise.resolve(`Hi! I'm ${this.name.first}`)
}
farewell(){
console.log(`${this.name.first} has left the building. Bye for now!`)
}
}
let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling'])
O método da classe pode ser usado da seguinte maneira:han.greeting().then(console.log)
Suporte do navegador
Um dos obstáculos ao uso de assíncrono / espera é a falta de suporte para navegadores mais antigos. Esse recurso está disponível em quase todos os navegadores modernos, além de promessas; Existem alguns problemas no Internet Explorer e no Opera Mini.Se você deseja usar async / waitit, mas precisa do suporte de navegadores mais antigos, pode usar a biblioteca BabelJS - ela permite usar o JS mais recente, convertendo-o em um navegador específico.Conclusão
Async / waitit permite escrever código assíncrono fácil de ler e manter. Embora assíncrono / espera seja pior do que outras maneiras de escrever código assíncrono, definitivamente vale a pena explorar.Obrigado pela atenção.Feliz codificação!