Resumo : neste tutorial, você aprenderá como escrever código assíncrono usando JavaScript async
/ await
palavras-chave.
Observe que para entender como funciona o async
/ await
, você precisa saber como funcionam as promessas .
Introdução às palavras-chave JavaScript assíncronas/aguardadas
No passado, para lidar com operações assíncronas, você costumava usar funções de retorno de chamada . No entanto, quando você aninha muitas funções de retorno de chamada, o código será mais difícil de manter. E você acaba com um problema notório conhecido como inferno de retorno de chamada.
Suponha que você precise realizar três operações assíncronas na seguinte sequência:
- Selecione um usuário do banco de dados.
- Obtenha serviços do usuário de uma API.
- Calcule o custo do serviço com base nos serviços do servidor.
As funções a seguir ilustram as três tarefas. Observe que usamos a setTimeout()
função para simular a operação assíncrona.
function getUser(userId, callback) {
console.log('Get user from the database.');
setTimeout(() => {
callback({
userId: userId,
username: 'john'
});
}, 1000);
}
function getServices(user, callback) {
console.log(`Get services of ${user.username} from the API.`);
setTimeout(() => {
callback(['Email', 'VPN', 'CDN']);
}, 2 * 1000);
}
function getServiceCost(services, callback) {
console.log(`Calculate service costs of ${services}.`);
setTimeout(() => {
callback(services.length * 100);
}, 3 * 1000);
}
Linguagem de código: JavaScript ( javascript )
Veja a seguir as funções de retorno de chamada aninhadas:
getUser(100, (user) => {
getServices(user, (services) => {
getServiceCost(services, (cost) => {
console.log(`The service cost is ${cost}`);
});
});
});
Linguagem de código: JavaScript ( javascript )
Saída:
Get user from the database.
Get services of john from the API.
Calculate service costs of Email,VPN,CDN.
The service cost is 300
Linguagem de código: JavaScript ( javascript )
Para evitar esse problema de retorno de chamada, o ES6 introduziu as promessas que permitem escrever código assíncrono de maneiras mais gerenciáveis.
Primeiro, você precisa retornar a Promise
em cada função:
function getUser(userId) {
return new Promise((resolve, reject) => {
console.log('Get user from the database.');
setTimeout(() => {
resolve({
userId: userId,
username: 'john'
});
}, 1000);
})
}
function getServices(user) {
return new Promise((resolve, reject) => {
console.log(`Get services of ${user.username} from the API.`);
setTimeout(() => {
resolve(['Email', 'VPN', 'CDN']);
}, 2 * 1000);
});
}
function getServiceCost(services) {
return new Promise((resolve, reject) => {
console.log(`Calculate service costs of ${services}.`);
setTimeout(() => {
resolve(services.length * 100);
}, 3 * 1000);
});
}
Linguagem de código: JavaScript ( javascript )
Então, você encadeia as promessas :
getUser(100)
.then(getServices)
.then(getServiceCost)
.then(console.log);
Linguagem de código: CSS ( css )
ES2017 introduziu as palavras-chave async
/ await
que se baseiam em promessas, permitindo que você escreva código assíncrono que se parece mais com código síncrono e é mais legível. Tecnicamente falando, o async
/ await
é um açúcar sintático para promessas.
Se uma função retornar uma promessa, você poderá colocar a await
palavra-chave na frente da chamada da função, assim:
let result = await f();
Linguagem de código: JavaScript ( javascript )
Eles await
aguardarão o Promise
retorno do f()
para se liquidar. A await
palavra-chave pode ser usada apenas dentro das async
funções.
O seguinte define uma async
função que chama as três operações assíncronas em sequência:
async function showServiceCost() {
let user = await getUser(100);
let services = await getServices(user);
let cost = await getServiceCost(services);
console.log(`The service cost is ${cost}`);
}
showServiceCost();
Linguagem de código: JavaScript ( javascript )
Como você pode ver, o código assíncrono agora se parece com o código síncrono.
Vamos mergulhar nas palavras-chave async/await.
A async
palavra-chave
A async
palavra-chave permite definir uma função que lida com operações assíncronas.
Para definir uma async
função, você coloca a async
palavra-chave na frente da palavra-chave da função da seguinte forma:
async function sayHi() {
return 'Hi';
}
Linguagem de código: JavaScript ( javascript )
Funções assíncronas são executadas de forma assíncrona por meio do loop de eventos . Ele sempre retorna um Promise
.
Neste exemplo, como a sayHi()
função retorna a Promise
, você pode consumi-la, assim:
sayHi().then(console.log);
Linguagem de código: CSS ( css )
Você também pode retornar explicitamente a Promise
da sayHi()
função, conforme mostrado no código a seguir:
async function sayHi() {
return Promise.resolve('Hi');
}
Linguagem de código: JavaScript ( javascript )
O efeito é o mesmo.
Além das funções regulares, você pode usar a async
palavra-chave nas expressões de função:
let sayHi = async function () {
return 'Hi';
}
Linguagem de código: JavaScript ( javascript )
let sayHi = async () => 'Hi';
Linguagem de código: JavaScript ( javascript )
e métodos de aulas:
class Greeter {
async sayHi() {
return 'Hi';
}
}
Linguagem de código: JavaScript ( javascript )
A await
palavra-chave
Você usa a await
palavra-chave para aguardar que um Promise
estado seja resolvido ou rejeitado. Você pode usar a await
palavra-chave apenas dentro de uma async
função:
async function display() {
let result = await sayHi();
console.log(result);
}
Linguagem de código: JavaScript ( javascript )
Neste exemplo, a palavra-chave instrui o mecanismo JavaScript a aguardar a conclusão await
da função antes de exibir a mensagem.sayHi()
Observe que se você usar o await
operador fora de uma async
função, receberá um erro.
Manipulação de erros
Se uma promessa for resolvida, o await promise
retorna o resultado. Porém, quando a promessa é rejeitada, await promise
ocorrerá um erro como se houvesse uma throw
declaração.
O seguinte código:
async function getUser(userId) {
await Promise.reject(new Error('Invalid User Id'));
}
Linguagem de código: JavaScript ( javascript )
… é o mesmo que isto:
async function getUser(userId) {
throw new Error('Invalid User Id');
}
Linguagem de código: JavaScript ( javascript )
No cenário real, demorará um pouco para que a promessa gere um erro.
Você pode detectar o erro usando a try...catch
instrução, da mesma forma que uma throw
instrução normal:
async function getUser(userId) {
try {
const user = await Promise.reject(new Error('Invalid User Id'));
} catch(error) {
console.log(error);
}
}
Linguagem de código: JavaScript ( javascript )
É possível detectar erros causados por um ou mais await promise
:
async function showServiceCost() {
try {
let user = await getUser(100);
let services = await getServices(user);
let cost = await getServiceCost(services);
console.log(`The service cost is ${cost}`);
} catch(error) {
console.log(error);
}
}
Linguagem de código: JavaScript ( javascript )
Neste tutorial, você aprendeu como usar a palavra-chave JavaScript async
/ await
para escrever código assíncrono que se parece com código síncrono.