O que está por vir no JavaScript em 2018

Photo of O que está por vir no JavaScript em 2018
Facebook
VKontakte
share_fav

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

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 = /(?\d{4})(?\d{2})(?\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!

ver iMasters
#javascript
#ecmascript
#asynchronous iteration