Front End

16 abr, 2018

O que está por vir no JavaScript em 2018

Publicidade

Todo programador, seja ele web ou não, nos últimos anos está se deparando com uma quantidade sem precedentes de mudanças nas linguagens de programação. Não é segredo que o JavaScript é, dentre estas linguagens, uma das que mais sofrem alterações drásticas em sua API constantemente.

Em 2015, tivemos a primeira grande alteração da API da linguagem com o ES6 e, desde então, a linguagem vem sofrendo cada vez mais melhorias para que suas funcionalidades sejam cada vez mais otimizadas e novos recursos sejam inseridos.

O processo de escolha, desenvolvimento e implementação destas funcionalidades é gerenciado pelo TC39, que é responsável por analisar, testar e verificar se todas as funcionalidades estão de acordo com o proposto. Todo o projeto é aberto e colaborativo! Então, isso significa que todos podem entrar lá e mandar uma Pull Request requisitando (ou até implementando) uma nova funcionalidade.

Desde o ES6 tivemos, mais ou menos, uma nova versão da especificação lançada por ano, e este ano não poderia ser diferente, o ES2018 está previsto para chegar em junho e já está oficializada pelo time.

Vamos dar uma olhada nas principais features desta nova versão.

Asynchronous Iteration

O ES6, dentre outras mudanças, nos trouxe os iterators. Estes objetos nada mais são do que estruturas que fornecem a funcionalidade de navegar entre itens em uma lista como, por exemplo, um array, e também seguem uma estrita convenção.

Todo iterator retorna o próximo item da lista da seguinte forma:

{
  value: Any,
  done: Boolean
}

E, além disso, cada iterator possui um método next() que nada mais faz do que retornar o objeto acima. Todos os arrays são – por definição – iterators, então podemos escrever algo desta forma:

let arr = [1, 2, 3, 4, 5]
let iterator = arr[Symbol.iterator]()

console.log(iterator.next().value) // 1
console.log(iterator.next().value) // 2
console.log(iterator.next().value) // 3
console.log(iterator.next().done) // false
console.log(iterator.next().value) // 4
console.log(iterator.next().value) // 5
console.log(iterator.next().done) // true

O problema aqui é que todos os iterators são síncronos. A grande novidade do ES2018 é torná-los assíncronos. O que, basicamente, significa que cada chamada de next() irá retornar uma Promise que poderá ser resolvida, portanto o código anterior viraria algo assim:

const { value, done } = iterator.next() // Aqui temos um iterator síncrono normal
asyncIterator.next() // isto nos retorna uma Promise<{ value, done }>

O que temos de fazer agora é utilizar a nova sintaxe for await of disponibilizada nessa mesma versão.

for await (const linha of readLines(arquivo)) { console.log(linha) }

Isto abre não só possibilidades maiores como iteração em arquivos linha a linha em tempo real ao invés de ter de esperar o arquivo todo ser carregado na memória antes de poder realizar qualquer ação sobre ele.

Mais detalhes podem ser vistos na documentação desta proposta.

Rest/Spread para objetos

Desde o ES6 já temos as chamadas rest/spread properties, que são basicamente os destructuring assignments utilizadas para decompor arrays em variáveis individuais.

let a, b, rest
[a, b] = [10, 20] // a = 10 e b = 20

Agora um exemplo usando rest:

let a, b, rest
[a, b, ...rest] = [1, 2, 3, 4, 5, 6] 
console.log(a) // 1
console.log(b) // 2
console.log(rest) // [3, 4, 5, 6]

Para ser curto e grosso, o ES2018 está introduzindo a mesma possibilidade para objetos. Portanto, poderemos fazer isso se utilizarmos rest:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }
x // 1
y // 2
z // { a: 3, b: 4 }

E spread, igualmente:

let n = { x, y, ...z }
console.log(n) // { x: 1, y: 2, a: 3, b: 4 }

Esta é uma proposta poderosa, porque nos abre várias portas, por exemplo, para filtrar um objeto, removendo suas propriedades desnecessárias de uma forma imutável. Imagine que temos um objeto de usuário, e queremos remover o e-mail deste objeto. Hoje fazemos assim:

const user = {
    firstName: 'Lucas',
    lastName: 'Santos',
    twitter: '_staticvoid',
    city: 'São Paulo',
    email: 'lucas.santos@santos.me',
}

const usuarioSemEmail = Object.assign({}, user)
delete usuarioSemEmail.email

O que não é necessariamente errado, mas temos problemas quando temos de executar esta tarefa para vários campos. Com a nova proposta poderemos fazer algo assim:

const {email, ...usuarioSemEmail} = user

Assim como toda a proposta, esta também tem uma documentação oficial que você pode conferir.

Promise.finally()

Esta foi uma feature muito requisitada desde o início das promises no JavaScript. Uma curiosidade sobre elas é que, apesar de serem oficialmente suportadas no ES6, as promises são um padrão de projeto muito utilizado pelos desenvolvedores JavaScript muito antes disso através de bibliotecas como o Bluebird e o Q.

Como todo desenvolvedor JavaScript, provavelmente já deve estar careca de saber, uma promise é definida por ser um constructo que executa uma ação assíncrona e encadeia um callback utilizando o método then() o que, por sua vez, leva uma função com os parâmetros retornados da execução. Caso tenhamos um problema com a tarefa assíncrona, utilizamos o método catch() para recuperar o erro e tratá-lo.

A grande novidade, que já era implementada nessas bibliotecas anteriores, é o uso do finally() da mesma forma como fazemos nos blocos try/catch atuais.

Hoje temos isto:

promise
.then(result => {···})
.catch(error => {···})

Com o ES2018 teremos um novo método finally() que será responsável por executar qualquer função ao final da execução da tarefa assíncrona, falhando ou não.

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {...})

Desta forma vamos continuar tendo a implementação padrão, com o acréscimo de um método que será sempre executado no final. Veja a documentação oficial para maiores detalhes!

RegExp: grupos nomeados

O ES2018 vai trazer não só esta, mas também outras mudanças no interpretador de Regex do JavaScript. Dentre elas, teremos:

Mas, na minha opinião, a mais importante de todas é o suporte a grupos nomeados. Quem já utilizou Regex deve saber que podemos separar nossas asserções em grupos, desta forma:

let regex = /(?\d{4})(?\d{2})(?\d{2})/u
let resultado = regex.exec('2018-04-10')

// resultado[0] => '2018-04-10'
// resultado[1] => '2018'
// resultado[2] => '04'
// resultado[3] => '10'

Mas veja que é um pouco complicado termos que trabalhar somente com os números dos índices. Para isso, uma nova sintaxe foi criada que nos permite dar nomes a cada um destes grupos:

let regex = /(?<ano>\d{4})(?<mes>\d{2})(?<dia>\d{2})/u
let resultado = regex.exec('2018-04-10')

// resultado.groups.ano => '2018'
// resultado.groups.mes => '04'
// resultado.groups.dia => '10'

A busca por índices continuará funcionando normalmente também.

Além destas features, outras propostas estão sendo discutidas no TC39 para melhorar ainda mais a interação com o interpretador RegExp dentro do JavaScript.

Com isso, fechamos grande parte do que está por vir neste ano no ES2018 e ficamos aguardando ansiosamente a chegada da nova especificação para que possamos, cada vez mais, realizar nossas tarefas de forma mais eficiente utilizando uma das linguagens que mais cresce no planeta!