Em vez disto:
let a = 'cat',
b = 2,
c = {};
// sem usar o atalho:
let obj = {a: a, b: b, c: c};
let a = 'cat',
b = 2,
c = {};
// shorthand property names
let obj = {a, b, c};
function getPosicaoMouse() {
return {x: getX(), y: getY()}
}
const posicao = getPosicaoMouse()
console.log(posicao.x)
console.log(posicao.y)
options
?
function filtraImagem(opcoes, imagem) {
// ...
if (opcoes.kernel === '3x3') {
// ...
}
if (opcoes.padding > 0) {
// ...
}
}
const opcoes = {
kernel: '5x5',
padding: 0,
shape: 'rect'
}
filtraImagem(opcoes, imagem)
// Exemplo (1): "desmontando"
let imgEl = doc...ector('#logo');
const { alt, src } = imgEl;
console.log(`alt = ${alt}`);
console.log(`src = ${src}`);
// do jeito old...
let imgEl = doc...ector('#logo');
const alt = imgEl.alt;
const src = imgEl.src;
console.log('alt = ' + alt);
console.log('src = ' + src);
// Exemplo (2): definindo o parâmetro de forma "destructured":
function desenhaGrafico({size = 'big', coords = {x: 0, y: 0}} = {}) {
console.log(size, coords, radius);
// desenha aqui...
//
}
desenhaGrafico({
coords: { x: 18, y: 30 },
size: 'small'
});
// do jeito old...
function desenhaGraficoES5(options) {
options = options || {};
var size = options.size || 'big';
var coords = options.coords || { x: 0, y: 0 };
console.log(size, coords);
// desenha aqui...
}
desenhaGraficoES5({
cords: { x: 18, y: 30 },
size: 'small'
});
const [head, ...tail] = [1, 2, 3, 4];
console.log(tail); // imprime [2, 3, 4]
let a = 1;
let b = 3;
[a, b] = [b, a]; // a=3, b=1
import
o que outros módulos export
math.js
:
export function fft1d(dados) {
// ... calcula transformada
// ...
return resultado
}
processa-imagem.js
:
import { fft1d } from './math.js'
export function compacta(imagem) {
return fft1d(imagem.dados)
}
<script type="module" src="principal.js"></script>
</body>
</html>
import
type="module"
instrui o navegador a considerar o arquivo como móduloexport
e import
export const nome = 'quadrado';
export function desenha(ctx, tam, x, y, cor) {
ctx.fillStyle = cor;
ctx.fillRect(x, y, tam, tam);
return {
tamanho: tam,
x,
y,
cor
};
}
export
:
var
, let
, const
export { nome, desenha }
export
e import
import { nome, desenha } from './geometria/quad.js'
import { area, perimetro } from './retangulos.js'
let quad = desenha(canvasEl.ctx, 50, 50, 100, 'blue');
area(quad.tamanho)
perimetro(quad.tamanho)
import
qualquer coisa que um módulo export
from
: deve ser um caminho relativo explícito ou completo import
e export
padrãoexport default
(padrão)import
, não precisará fazer destructuring. Exemplo:
abelha.js
export default class Abelha {
static IMAGEM = 'imgs/abelha.gif'
constructor(y) {
this.y = y
}
desenha(ctx) {
// ...
}
atualiza() {
// ...
}
}
principal.js
import Abelha from './abelhas.js'
let abelhas = [
new Abelha(Math.random()),
new Abelha(Math.random()),
new Abelha(Math.random())
]
import('./filtros/convolucao.js')
.then(modulo => {
// módulo carregado
});
Problema
~
quando precisamos realizar várias chamadas assíncronas, podemos
ter um callback hell: várias callbacks aninhadas
- Dificulta a leitura e escrita
- Suscetível a erros do programador
- Trata erros apenas por callback, dificultando
a legibilidade/manutenibilidade do código
Soluções
~ uso de promessas explicitamente ou com async/await
Imprimir (4) todas as “pessoas”
(3) da mesma espécie do
(2) primeiro residente do
(1) planeta Naboo
id=8
)
sendAjax('https://swapi.dev/api/planets/8', planeta => { // Naboo
sendAjax(planeta.residents[0], residente => { // R2-D2
sendAjax(residente.species, especie => { // Droid
// pega todas as "pessoas" dessa espécie
for (let pessoa of especie.people) {
sendAjax(pessoa, p => {
console.log(p.name + ', ') // ordem pode mudar!
})
// C-3PO, R2-D2, R5-D4, IG-88, BB8,
}
})
})
})
id=8
)sendAjax('https://swapi.dev/api/planets/8') // Naboo
.then(planeta => sendAjax(planeta.residents[0])) // R2-D2
.then(residente => sendAjax(residente.species)) // Droid
.then(especie => Promise.all(especie.people.map(pessoa => sendAjax(pessoa))))
.then(pessoas => console.log(pessoas.map(p => p.name).join(', ')))
// C-3PO, R2-D2, R5-D4, IG-88, BB8
.catch(erro => console.error(`Deu ruim: ${erro}`));
.then
,
passando uma função que só será chamada quando a promessa for cumprida
(com êxito ou falha)
.then(callbackSuccess, callbackError)
pode receber 2 funções.catch
para tratar o erro de uma “promise chain”
de forma genéricaPromise
de forma que nós definimos
quando elas estão resolvidas (com sucesso ou falha)
Exemplo: aguardar 2s antes de fazer algo
function espera2s() {
return new Promise(resolver => {
setTimeout(resolver, 2000)
})
}
espera2s()
.then(() => console.log('2s depois'))
tempo
antes de fazer algo (apenas parametrizando)
function espera(tempo) {
return new Promise(resolver => {
setTimeout(resolver, tempo*1000)
})
}
espera(5)
.then(() => console.log('5s depois'))
await
em vez de .then
async
para retornar Promise
await
.then
encadeados reduzem (mas não acabam) com callback hell 🔥.catch
não capturar exceção
.catch
seja atrasado (eg, devido a alguma espera na criação da promessa - exemplo)await
```js function espera(tempo) { return new Promise(resolver => { setTimeout(resolver, tempo*1000) }) }
console.log('tempo = 0')
await espera(2) // <--
console.log('tempo = 2')
// tempo = 0
// ...
// tempo = 2 (2s depois)
console.log('tempo = 0')
espera(2).then(() => console.log('tempo = 2'))
// tempo = 0
// ...
// tempo = 2 (2s depois)
await
substitui o .then
await funcao()
const db = {/*...*/}
function dados(entidade) {
return new Promise(resolver => {
// faz algo assíncrono (eg, acessa banco ou ajax)
// e resolve (cumpre) a promessa com o resultado
resolver(db[entidade])
})
}
// com await 🎉
const noticia = await dados('noticias')
const template = await formata(noticia)
mostraNoticia(template)
// com promise.then
dados('noticias')
.then(formata)
.then(mostraNoticia)
Promise
é retornado
pela funçãomostraNoticia() << formata() << dados('noticia')
// com await 🎉
const noticia = await dados('noticia')
const autor = await dados(`autor/${noticia.autor}`)
mostraNoticia(noticia, autor)
// com promise.then
dados('noticia')
.then(noticia => {
return dados(`autor/${noticia.autor}`)
.then(autor => mostraNoticia(noticia, autor))
})
mostraNoticia() << noticia, autor
autor << noticia
.then
,
o código perde legibilidade
await
o código parece síncrono (ficando mais legível)try / catch
, mas eles não funcionam com Promise
.catch
ou passar uma errorCallback
como 2º argumento para .then
Se usarmos await
, podemos usar try / catch
sem problemas:
// com await 🎉
try {
const noticia = await dados('noticias')
const template = await formata(noticia)
mostraNoticia(template)
} catch (erro) {
mostraUmaPropaganda()
console.error(erro)
}
// com promise.catch
dados('noticias')
.then(formata)
.then(mostraNoticia)
.catch(erro => {
mostraUmaPropaganda()
console.error(erro)
})
async
await
, foi introduzida async
await
é permitido apenas dentro de funções async
Promise
// com async
async function responder() {
return 42
}
// promise explícita
function responder() {
return Promise.resolve(42)
}
async
sempre retorna uma Promise
:
async function hello() {
return 'Hello';
}
const b = hello();
console.log(b);
// ❌ [object Promise]
b.then(texto =>
console.log(texto))
// ✅ 'Hello'
async/await
vs Promise
try {
const planeta = await sendAjax('https://swapi.dev/api/planets/8') // Naboo
const residnt = await sendAjax(planeta.residents[0]) // R2-D2
const especie = await sendAjax(residnt.species) // Droid
const pessoas = await Promise.all(especie.people.map(pessoa => sendAjax(pessoa)))
console.log(pessoas.map(p => p.name).join(', '))
// C-3PO, R2-D2, R5-D4, IG-88, BB8
} catch(erro) {
console.error(`Deu ruim: ${erro}`)
}
sendAjax('https://swapi.dev/api/planets/8') // Naboo
.then(planeta => sendAjax(planeta.residents[0])) // R2-D2
.then(residnt => sendAjax(residnt.species)) // Droid
.then(especie => Promise.all(especie.people.map(pessoa => sendAjax(pessoa))))
.then(pessoas => console.log(pessoas.map(p => p.name).join(', ')))
// C-3PO, R2-D2, R5-D4, IG-88, BB8
.catch(erro => console.error(`Deu ruim: ${erro}`));
sendAjax('https://swapi.dev/api/planets/8', planeta => { // Naboo
sendAjax(planeta.residents[0], residente => { // R2-D2
sendAjax(residente.species, especie => { // Droid
// pega todas as "pessoas" dessa espécie
for (let pessoa of especie.people) {
sendAjax(pessoa, p => {
console.log(p.name + ', ')
})
// C-3PO, R2-D2, R5-D4, IG-88, BB8,
}
})
})
})
sendAjax('https://swapi.dev/api/planets/8') // Naboo
.then(planeta => sendAjax(planeta.residents[0])) // R2-D2
.then(residente => sendAjax(residente.species)) // Droid
.then(especie => Promise.all(especie.people.map(pessoa => sendAjax(pessoa))))
.then(pessoas => console.log(pessoas.map(p => p.name).join(', ')))
// C-3PO, R2-D2, R5-D4, IG-88, BB8
.catch(erro => console.error(`Deu ruim: ${erro}`));
async-await
try {
const planeta = await sendAjax('https://swapi.dev/api/planets/8') // Naboo
const residnt = await sendAjax(planeta.residents[0]) // R2-D2
const especie = await sendAjax(residnt.species) // Droid
const pessoas = await Promise.all(especie.people.map(pessoa => sendAjax(pessoa)))
console.log(pessoas.map(p => p.name).join(', '))
// C-3PO, R2-D2, R5-D4, IG-88, BB8
} catch(erro) {
console.error(`Deu ruim: ${erro}`)
}
// ❌ espera sem precisar
async function mensagem() {
const a = await quem()
const b = await oque()
const c = await onde()
console.log(`${a} ${b} ${c}`)
}
// ✅ faz a,b,c em paralelo
async function mensagem() {
const todas = Promise.all([
quem(), oque(), onde()
])
const [a, b, c] = await todas
console.log(`${a} ${b} ${c}`)
}
::: Quando atividades não possuem dependência entre si, podemos executá-las em paralelo
Promise.all()
ou Promise.allSettled()
Promise.race()
: resolve ou rejeita assim que a primeira resolve ou rejeitaPromise.any()
: resolve quando a 1ª resolverconsole.log << quem(), oque(), onde()
function espera(tempo) {
return new Promise(resolver =>
setTimeout(resolver, tempo))
}
async function quem() {
await espera(200)
return '🤡'
}
async function oque() {
await espera(300)
return 'espreita'
}
async function onde() {
await espera(500)
return 'nas sombras'
}
async function mensagem1() { // ❌
const a = await quem()
const b = await oque()
const c = await onde()
console.log(`${a} ${b} ${c}`)
}
mensagem1() // depois de 1s: (esperou pra +)
// 🤡 espreita nas sombras
async function mensagem2() { // ✅
const todas = Promise.all([quem(), oque(), onde()])
const [a, b, c] = await todas
console.log(`${a} ${b} ${c}`)
}
mensagem2() // depois de 500ms:
// 🤡 espreita nas sombras
await
await
só podia ser usado dentro de funções async
await Promise.resolve(console.log('🎉'));
// → SyntaxError: await is only valid in async function
(async function() {
await Promise.resolve(console.log('🎉'));
// → 🎉
}());
await Promise.resolve(console.log('🎉'));
// → 🎉