Promises Javascript: saiba o que é e como usar!

Otimizar o tempo dentro do código é essencial, e, nessa perspectiva, muito se tem falado a respeito de Promises em JavaScript. Nesse momento, imaginamos que pelo nome talvez você não consiga compreender do que se trata essa tal promessa. 

Então, nesse post você verá desde os conceitos básicos, como usar, como criar uma Promise e exemplos, tudo reunido em um lugar só, o seu verdadeiro guia para compreender esse conceito. 

O que é uma promise?

Promises é um objeto em JavaScript que permite a execução de processamentos de forma assíncrona dentro do seu código, uma vez que é definido como um objeto onde é possível guardar valores que poderão ser usados em outro momento no seu código enquanto você executa outras tarefas. Desse modo, tudo isso será necessário para retratarmos processamentos de sucesso ou falhas dentro do nosso código.

Além disso, é importante sabermos que uma Promise estará em diferentes estados.

História das promises

Mas, afinal, como surgiram as Promises? 

Primeiramente, para a computação, os seus conceitos começaram a surgir ainda na década de 70, porém eram conhecidas por outros termos, como futures, promise deferred ou delay. Todos esses são definidos como construtos utilizados na sincronização do processamento de um código em diferentes linguagens.

Desse modo, são responsáveis por descrever um objeto que age como um proxy para gerar um valor/resultado inicialmente  desconhecido, visto que o seu direcionamento pode ainda não estar concluído no momento da chamada do programa.

Nessa perspectiva, esses termos expressam um compromisso ou uma relação temporal entre dois eventos. Assim, com o tempo e os avanços da computação, o termo promises deu um novo significado a programação assíncrona.

Nessa sequência, em meados de 2007, a sua utilização intensificou-se em diferentes bibliotecas, como MochiKit, Dojo  e o jQuery . Logo,  o grupo CommonJS criou uma série de especificações com a finalidade de padronizar as implementações e estipular regras para definir o que seria uma Promise utilizando uma especificação conhecida como Promise/A+. 

Processamento assíncrono

Neste momento, nós já contextualizamos um pouco acerca do surgimento da Promise, então vamos detalhar um pouco mais como funciona esse processamento assíncrono. 

Assim sendo, primeiro vamos ilustrar um exemplo prático do dia a dia para tentar relacionar com um fluxo assíncrono em programação:

Imagine a seguinte situação: você e a pessoa que mora com você precisam realizar uma faxina na casa para colocar as coisas em ordem. Nesse momento, enquanto você está lavando a louça, você percebe que os produtos de limpeza estão acabando. Então, logo você se depara com o seguinte dilema: “posso ir comprar os produtos que estão faltando e depois continuar a faxina, ou eu peço para a outra pessoa ir até o supermercado mais próximo e comprar os produtos enquanto eu otimizo as tarefas de limpeza dentro do nosso apartamento”.

Nesse caminho, vocês dois conversam e criam uma lista de prós e contras, chegando a conclusão de que vocês finalizariam as atividades domésticas muito mais rápido se dividissem as tarefas e, enquanto um de vocês for comprar os produtos, a outra pessoa ficará em casa limpando os utensílios necessários com a quantidade de produto que ainda resta. Aqui você já percebeu que essa ideia foi muito inteligente para otimização do tempo.

Dessa maneira, em linguagens de programação, chamamos esse tipo de procedimento de assíncrono. Você poderia ter esperado pela outra pessoa para concluir a atividade juntos, mas, optar por uma divisão de tarefas foi importante para que o tempo de vocês fosse potencializado.

Desse jeito, quando nos referimos a JavaScript, sabemos que é uma linguagem que nos fornecerá suporte a programação assíncrona, ou seja, estamos lidando com resultados que ainda não temos, mas que serão processados logo em seguida. 

Além disso, é importante destacar que o ES6 tornou o fluxo de tarefas assíncronas mais fácil graças à criação de uma Promise. Dessa forma, é possível ter um espaço reservado que executará as atividades enquanto lidamos com outras demandas, visto que isso otimiza o nosso tempo enquanto construímos nosso código.

Como funcionam as promises?

Quando estamos programando, nem sempre sabemos definir quais as variáveis ou valores que deverão ser utilizados no código. Dessa forma, surge uma Promise em JavaScript. Logo, são criados métodos que permitem ações assíncronas para gerir os eventos no código. 

A Promise será uma ação executada no futuro do código, podendo assumir vários estados. Ou seja, ela poderá ser resolvida (obter sucesso)  ou retornar algum erro (rejeitada). Dessa maneira, o método Then  verificará se houve um caso de erro ou sucesso na execução do código, no qual retornará o método resolve quando houver sucesso e reject no caso de erros. O fluxo de execução do código se dará da seguinte forma:

Compreensão de uma Promises JavaScript

Encadeamento com then() e catch()

O encadeamento é essencial para entender como o código funcionará, uma vez que isso determina uma sequência de direcionamentos dentro do código. Nesse sentido, o encadeamento de Promises com then e catch vai direcionar os nossos resultados. Para entendermos de forma prática, vamos visualizar o seguinte exemplo:

const teste = new Promise ((resolve, reject) => {
	setTimeout(() = > resolve ('Promise resolvida'), 3000)
})
 
// Aqui os callbacks estão ligados a teste
 
teste.then((res) => {}, (rej) => {})
 
// Nessa parte, observamos o mesmo resultado
 
new Promise ((resolve, reject) => {})
	.then((res) => {}, (rej) = {}

Podemos combinar bem o resolve com o then, que retornará sucesso, ou o reject com o catch, para falha/erro.

Além dessa forma de encadeamento, temos ainda o Async que é uma aplicação presente no ECMAScript. Essa função pode aceitar N funções em si, uma vez que será repassado dentro da pipeline do código. Nessa perspectiva, esse é um ponto importante, pois, na estruturação do seu código, nem todas as funções serão assíncronas, ou seja, a execução será realizada na ordem correta de funcionamento.

Quando e por que utilizar uma promise?

Na estruturação de um código, a criação de funções assíncronas auxiliam no fluxo do código. A exemplo disso, ela pode ser utilizada no momento de processamento de imagens no programa. 

Nesse sentido, manter uma padronização no código também é fundamental para manter a organização, uma vez que em uma implementação que demanda o auxílio de diferentes pessoas a legibilidade torna-se essencial. 

Sintaxe

Agora, vamos falar um pouco sobre como funciona a sintaxe na criação de uma Promise. 

Para criar objetos em JavaScripts, chamamos a palavra reservada new, logo, o código ficaria da seguinte maneira



 Promise();

No entanto, antes de executar essa linha de código, é importante lembrar que é necessário passar os parâmetros do seu objeto para que a execução tenha êxito. No caso, precisamos escrever uma função que seja capaz de resolver ou rejeitar a Promise. 



new Promise((resolve: Function, reject: Function) => void)

Pronto, agora você já sabe como funciona a sintaxe na criação de uma Promise.

Quais os 4 principais estados de uma promise?

Agora, vamos falar um pouco sobre os 4 estados de uma Promise

  • Pending

Como a própria tradução da palavra, o estado da Promise ainda é pendente. Ou seja, é quando a sua Promise não passou pelo processo de ser fulfilled (sucesso) ou rejected (rejeitada).

  • fulfilled

No inglês, também é conhecida como “resolved”, ou seja, é quando nossa Promise foi realizada com sucesso.

  • rejected

Nesse estado, a Promise é rejeitada, ou seja, a operação falha.

  • Settled

Essa é a etapa final da Promise, uma vez que vemos a conclusão e saberemos se ela foi resolved (realizada) ou rejected (rejeitada).

Métodos e Propriedades das promises

a) Propriedades

  •  Promise.length

A propriedade length é responsável pelo número de argumentos do construtor, o valor sempre será 1.

  • Promise.prototype

Propriedade protótipo responsável pelo método construtor da Promise.

b) Métodos 

  • Promise.all  

Esse método retornará todas as promisses que estiverem presentes no argumento. Por exemplo, no caso de uma promisse.all(lista), o argumento será responsável por retornar sempre que a Promise for resolvida ou rejeitada. Nesse sentido, se Promise for resolvida, será aplicado um array para mostrar as promises dessa lista.

  • Promise.race  

Esse método retornará o valor de uma Promise ou motivo pelo qual ela está sendo resolvida ou rejeitada. 

  • Promise.reject 

Esse método é responsável por retornar os objetos promises que foram rejeitados e o seu motivo.

  • Promise.resolve  

Esse método é responsável por retornar os objetos do promises que foram resolvidos e o seu valor. Uma curiosidade legal na construção do seu código é que você pode consultar se o valor é uma promise. Para isso, você só precisa utilizar o comando “promise.resolve(valor) para visualizar o valor de uma promise. 

Criando a primeira Promise: aprenda na prática!

Agora que nós já estudamos um pouco sobre a teoria de uma Promise, que tal começarmos a criar os nossos códigos?

Então, venha conosco e vamos colocar a mão na massa! Para exemplificar, primeiro vamos criar uma função teste para simular:


function teste()

}

Logo, poderemos criar a nossa Promise e para isso utilizamos a palavra reservada new. Então, atenção! É importante lembrar que Promise é um objeto em JavaScript, portanto seguirá a mesma nomenclatura. 



new Promise ();

Agora, não esqueça! Apenas chamar a função no seu código retornaria um erro, pois precisamos definir os parâmetros que serão responsáveis por resolver (resolve) ou rejeitar (reject) a nossa Promise. Desse modo, o nosso código ficará com essa aparência:

function teste() { 

new Promise((resolve, reject) => { 

});

}

Promises javascript: Exemplos práticos!

Agora que a gente já conversou um pouco sobre a estruturação de uma Promise e mostramos como é o funcionamento assíncrono dos fluxos, vamos ilustrar um exemplo de código prático para fixar mais ainda como eles atuam no código.

Imagine o cenário em que você quer resolver (resolve) ou rejeitar (reject) a sua Promise. Aqui criaremos funções de retorno de chamada em que podemos usar o valor para outros fins.

Para que isso ocorra, criaremos as condições responsáveis por resolver ou rejeitar a Promise. Para a criação da função de sucesso, criamos uma string chamada “vermelho” e para a função de falha, criamos uma string que diz “azul” (lembrando que são casos representativos):

//caso de sucesso

const promise = new Promise((resolve, reject) =>{

var twoMinutes = 2 * 60 * 1000 // 2mins

setTimeout(()=>{ resolve ("vermelho")}, twoMinutes)

})

//caso de falha

const promise = new Promise((resolve, reject) =>{

var twoMinutes = 2 * 60 * 1000 // 2mins

setTimeout(()=>{ resolve ("azul")}, twoMinutes)

})

Nesse momento, a Promise iniciará automaticamente o processamento do argumento para resolvê-lo para o onFullfilled e também trará o argumento de rejeição para o OnFailure.

//caso sucesso

const onFulfilled = (result) => {

console.log(result, "proximo passo")

}

//caso falha

const onFailure = (error) => {

console.log(error, "mais uma vez")

}

Esses dois casos no retorno da chamada recebem parâmetros que serão retornados quando a Promise for processada.

//caso de sucesso

promise.then(onFulfillment)

output> vermelho proximo passo

//caso de falha(onFailure)

output> azul mais uma vez

Em outros cenários, poderíamos ter vários modelos de resultados, como uma matriz, um objeto (JSON), ou outros tipos de dados retornados em operações assíncronas.

Compatibilidade com navegadores

A compatibilidade com navegadores é um ponto a ser colocado em destaque para que você não fique quebrando a cabeça com soluções sem fundamento. Então, fique atento aos principais navegadores que são suportados. 

  • Dispositivos Web
    • Chrome
    • Edge
    • Firefox
    • Opera
    • Safari
  • Dispositivos Móveis
    • WebView Android
    • Chrome Android
    • Firefox for Android
    • Opera Android
    • Safari on iOS
    • Samsung Internet

É importante verificar que não é suportado pelo Internet Explorer e, também, verificar as especificações de cada suporte antes de iniciar a sua aplicação.

Como foi visto, o conceito e aplicações de Promises em JavaScript é essencial 

para o bom funcionamento do código, permitindo ao programador ou programadora maior liberdade e otimização durante a construção. 

Agora que você já entendeu um pouco mais do conceito, recomendo o aprofundamento nas aplicações da linguagem JS e suas funções, assim como a função JavaScript Alert!