Como trabalhar com Async / Await e entendendo Promises.

Entenda como trabalhar com Async/Await

Promises

Antes de falar sobre async / await é preciso entender Promises.

Promises JavaScriptPromise, ou Promessa, é um objeto usado para processamento assíncrono.
Uma Promise representa um valor que pode estar disponível agora, no futuro ou nunca.
Usando uma Promise, é assegurado que a API não será processada nem formatada até que a chamada da API seja bem sucedida.

Estados de uma Promise :

  • pending (pendente): Estado inicial, que não foi realizada nem rejeitada.
  • fulfilled (realizada): sucesso na operação.
  • rejected (rejeitado):  falha na operação.
  • settled (estabelecida): Que foi realizada ou rejeitada.

Função assíncrona com Promises.

const fetch = require('node-fetch')

function getPerson(id){
	fetch(`http://swapi.co/api/people/${id}`)
		.then(response => response.json())
		.then(person => console.log(person.name))
}

getPerson(1) //Luke Skywalker

NOTA:

As funções resolve e reject, quando chamadas, resolvem (em caso de sucesso)ou rejeitam (quando ocorre um erro)a promessa, respectivamente. O executor começa o trabalho assíncrono que, quando concluído, chama uma das funções resolve ou reject para definir o estado da promessa.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Promise

Async

A declaração async function define uma função assíncrona, que retorna um objeto AsyncFunction, em JavaScript a função assíncrona é por definição um objeto do tipo AsyncFunction.

Para se obter melhor eficiência é recomendado que a função seja declarada com o async, ou seja, com a expression async functions chamado no código, desta forma as funções são tratadas com o resto do código, pois o mesmo sendo criado através do construtor AsyncFunction as funções são tratados na criada, perdendo eficiência.

Exemplo 1 : Declarando uma função async apartir da expression async functions.

async function newFunction("/*... Parametros */") {
    /*... Declarações ... */
}

Exemplo 2 : Declarando uma função async através do construtor de uma AsyncFuntion

let AsyncFunction = Object.getPrototypeOf(async function(){}).constructor

let newFunction = new AsyncFunction(/*Aqui é aplicado todo escopo da função, parâmetros, declarações, retorno.*/)

newFunction('/* Parâmetros */').then(v => {
  console.log(v); // imprime o resultado.
})
  • Observamos Claramente que o Exemplo 1 não só é mais prático, como é é simples e de aplicar e entendimento.

NOTA:

Uma função assíncrona pode conter uma expressão await, que pausa a execução da função assíncrona e espera pela resolução da Promise passada, e depois retorna o valor resolvido.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/async_function

Await

O operador await é utilizado para esperar por uma Promise . Ele pode ser usado apenas dentro de um escopo async function.

A expressão await, como o próprio nome diz “Aguardando”, ou seja, enquanto o processo não obtiver retorno a função async fica em pausa, esperando o retorno da Promise, se a Promise for rejeitada a expressão await executa uma Exception com o valor da Rejeição.

Exemplo:

async function newFunction() {
	try{
		return await Promisefunction('/* parametros */')
	}catch(e){
		return e
	}
}
console.log(newFunction())

NOTA:

Se o valor não for uma Promise, ele converte o valor para uma Promise resolvida,  e espera por ele.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/await

Exemplo 1: Escrevendo uma função assíncrona com async/await

const fetch = require('node-fetch')

function getPerson(id){
	const response = await fetch(`http://swapi.co/api/people/${id}`)
	const person = await response.json()
	console.log(person.name)
}

getPerson(1) //Luke Skywalker
  • Note que no exemplo acima existe duas expressões await, neste caso quando a primeira esta em execução a função entra em pausa aguardando o retorno da promise, assim que recebe o retorno a função sai da pausa passando para a próxima linha de execução, entrando novamente em pausa e assim poder finalizar todo o processo.

Exemplo 2: Com Arrow Function

const fetch = require('node-fetch')

function getPerson(id){
	const response = await fetch(`http://swapi.co/api/people/${id}`)
	return await response.json()
}

getPerson(1)
	.then(person => console.log(person.name) //Luke Skywalker
  • Neste exemplo temos o mesmo processo do exemplo anterior, mais desta vez utilizando Arrow functions, também podemos notar a notação do then, isto só é possível porque o retorno é uma Promise.

Exemplo 3: Utilizando Promise.all, Arrow function, Map

const fetch = require('node-fetch')
const ids = [1, 2, 3, 4, 5]
let person = []

function getPerson(id){
	const response = await fetch(`http://swapi.co/api/people/${id}`)
	const person = await response.json()	
	return person.name
}

function getData(){
	person.push(Promise.all(ids.map(item => getPerson(item)))
	return person[0]
}

async function result (){
	console.log(await getData())
}

result()
	/*[ 'Luke Skywalker',
		'C-3PO',
		'R2-D2',
		'Dart Vader',
		'LEia Organa' ] */

Para finalizar Deixo este código para Reflexão, Abraço e até o Próximo Post!

Trabalhando com map, filter e reduce

Entenda os comportamentos e funcionalidades, de forma Prática e direta.

Map

map é um método que executa um callback para cada valor de um array modificando os mesmos, isso faz com que o map crie um novo array com os novos valores obtidos.

Quando utilizar?

Quando você quer que o resultado seja um “array” com “o mesmo” tamanho do “array” inicial, porém com valores modificados (ou não).

Funciona da seguinte maneira:

  • recebe 1 elemento do array.
  • executa a função passada.
    • –adiciona esse elemento no array de resposta.

Aplicação Básica

const array = ['values'];

const arrayResp = array.map(function(value){
	//...Aqui é aplicado o Código de execução que retorna a interação para o arrayResp.
});

console.log(arrayResp);

Exemplo 1: Básico

let list = [1,2,3].map(function(value){
	return value * 2;
});

console.log(list); //[2, 4, 6]
  • Basicamente o método este percorrendo o array e fazendo a multiplicação de cada valor por 2, e a cada soma o resultado é adicionado a variável list, tendo por fim a impressão no console o array [2, 4, 6].

Exemplo 2: Com Arrow Functions

const list = [1,2,3];

let multipliedByTwo = list.map(x => x * 2);

console.log(multipliedByTwo); //[2, 4, 6]
  • Neste exemplo temos o mesmo processo do exemplo anterior, com algumas modificações e a utilização do Arrow functions, desta forma podemos ter um código mais curto (limpo) sem perder a essência.

Exemplo 3: Com Promises

const list = [1,2,3];
let multipliedByTwo = [];

const functionWithPromise = item => {
	return Promise.resolve(item * 2);
}

const anAsyncFunction = async item => {
	return await functionWithPromise(item);
}

const getData = async () => {
	multipliedByTwo.push(
		await Promise.all(
			list.map(item => anAsyncFunction(item))
		)
	);
	return multipliedByTwo[0];
}

async function result(){
	console.log(await getData());
}

result(); // [2 ,4, 6]
  • Agora Observamos um exemplo mais trabalhado, utilizando Promises, simplificando, o map é executado dentro do escopo da Promises.all, neste formato o map é completamente executado e retorna um array com os valor somados, depois é feito o “push” para o variável multipliedByTwo, ou seja, é obtido um array e aplicado dentro do outro, por este motivo o retorno da função getData esta “pegando” o item [0], imprimindo por fim o mesmo resultado dos exemplos anteriores.

NOTA:

O método map não modifica o array original. No entanto, a função callback invocada por ele pode fazê-lo.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Filter

Como o nome já diz essa função server para filtrar elementos de um array para um novo. O filter assim como o map, e outros, também é um Functor logo não modificará nosso array original.

Quando utilizar?

Quando você quer que o resultado seja um “array” com o tamanho menor (ou não) que o “array” inicial, porém ”apenas” com valores que passaram por um teste lógico.

Funciona da seguinte maneira:

  • recebe 1 elemento do array.
  • executa a função passada.
    • –caso o retorno seja true.
      • adiciona esse elemento no array de resposta.
    • –caso o retorno seja false.
      • NÃO adiciona esse elemento no array de resposta.

Aplicação Básica

const array = ['values'];

const result = array.filter("//...Aqui é aplicado o Código de execução que retorna o resultado que for 'true' para o result.");

console.log(result);

Exemplos Simples utilizando Arrow Functions:

const list = [1, 5, 9, 8, 2, 10, 3, 4];

let greaterThanFive = list.filter(number => {return number > 5});

console.log(greaterThanFive) //[9, 8, 10]
  • No exemplo acima é aplicado o Arrow functions dentro do escopo do filter retornando apenas os números maiores que 5, criando um novo array na variável greaterThanFive.

Exemplos Simples utilizando Arrow Functions e If ternário:

const list = [1, 5, 9, 8, 2, 10, 3, 4];

let oddNumbers = list.filter(number => (number % 2 == 1 ? true : false));

console.log(oddNumbers) //[1, 5, 9, 3]
  • Neste exemplo junto com o Arrow functions, também esta aplicado o if ternário dentro do mesmo escopo do filter retornando apenas os números ímpares, criando um novo array na variável oddNumbers.

NOTA:

filter não altera o array a partir da qual foi invocado.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filtro

Reduce

Método que executa uma função de redutor (que você fornece) em cada elemento da matriz, resultando em um único valor de saída.

Quando utilizar?

Quando você quer que o resultado seja um “array” (ou qualquer outro tipo existente) e seu(s) o(s) valor(es) pode(m) ser de qualquer tipo.
Ainda pode-se falar que quando precisa iterar o mesmo array usando filter e map, ao invés de fazê-lo duas vezes, o reduce, mesmo sendo mais complexo, é uma opção para isso. Dentro dele dá para em uma interação fazer o que é preciso de um filter e um map.

Funciona da seguinte maneira:

  • A função de redutor usa quatro argumentos: –
    • Acumulador (acc)
    • –Valor Atual (cur)
    • –Índice atual (idx)
    • –Matriz de Origem (src)
  • O valor retornado da sua função redutor é atribuído ao acumulador, cujo valor é lembrado em cada iteração em todo o array e, finalmente, torna-se o valor resultante final único.

Aplicação Básica

const array = ['values'];

const result = array.reduce(function(accumulator, currentValue){
	//... Aqui é aplicado o Código de execução que retorna o resultado para o result.
});

console.log(result);

Exemplos Simples utilizando Arrow Functions:

const list = [1, 2, 3, 4];

const totalSum = list.reduce((accumulator, currentValue) => {
	return accumulator + currentValue;
});

console.log(totalSum); //10
  • No exemplo acima o reduce executa a soma de todas as interações, retornando o valor a soma total na variável totalSum, explicado com mais detalhes no próximo exemplo.
const list = [1, 2, 3, 4];

const reducer = (accumulator, currentValue) => accumulator + currentValue;

console.log(list.reduce(reducer)); //10

console.log(list.reduce(reducer, 5)); //15
  • No exemplo acima foi criada a função reducer, com os parâmetros accumulator & currentValue, onde temos a aplicação da função interna do reduce, desta forma trabalhamos de uma forma mais abrangente.

    1 – Observamos que no primeiro console, passamos apenas como parâmetro a função reducer, isso porque no método reduce o seu primeiro parâmetro é um acumulador, desta forma a primeira interação apenas o acumulador é preenchido, ou seja, no reducer o parâmetro (variável) accumulator, recebe o valor inicial e fica aguardando os demais valores, do segundo em diante, “se existir“, os valores são colocados no parâmetro (variável) currentValue, somando o accumulator com o currentValue , até chegar a ultima interação, por fim imprimindo no console o valor final, neste caso “10”.

    2 – No Segundo Console observamos que diferente do primeiro são passados dois parâmetro no método reduce, como explicado no primeiro console, o método reduce tem como primeiro parâmetro um acumulador, certo, mais se o primeiro é um acumulador, como é que ele trabalha passando 2 parâmetro?, Isto se da por conta de sua estrutura original, na verdade, o reduce recebe valores implícitos, assim como no primeiro console ele recebe a função reducer, que sua estrutura são dois parâmetro, neste caso ele recebe a mesma função, executa por inteiro este primeiro parâmetro “reducer”, que o retorno se torna o acumulador e tem como valor corrente o próximo parâmetro “5”, por fim somando o acumulador com o valor corrente e imprimindo no console o resultado da soma “15”.

NOTA:

Se o valorInicial não tiver sido passado como argumento, então Acumulador
 será igual ao primeiro valor no array e valorAtual será igual ao segundo.

Referência: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Atenção:

Todos os Três métodos, map, filter e reduce, só funciona com array, mais existem particularidades que deverão ser “SEMPRE” levadas em considerações.
1 – Garanta “SEMPRE” que será um array que chamará os métodos:

  • Se não for um array, será executado uma exceção de erro que por sua vez quebra todo o processo.

2 – O Array pode ser Vazio?

  • Para o map & filter se o array tiver vazio, os métodos retornarão um array vazio.
  • Para o reduce, se o array tiver vazio, o método executa uma exceção do erro, quebrando todo o processo, desta forma é de suma importância que ao ser utilizado o método reduce, que seja garantido que o array tenha no mínimo um Valor, ou seja, é necessário Sempre testar se o array origem não esta vazio, pois o reduce só funciona se o array origem tiver amenos um valor.

Exemplos Simples para o teste:

let list;
// ou
let list = [];

const result = Array.asArray(list) && list.length > 0 
	? list.reduce((accumulator, currentValue) => accumulator + currentValue)
	: 0
	
console.log(result) //0
  • O teste pode ser feito de várias formas, no exemplo acima, foi propositalmente aplicado um “if ternário” para garantir um valor de retorno, mais podemos apenas criar um “if” padrão executando (no caso do reduce) se for um array e não estiver vazio, para o map & filter não se faz necessário testar se esta vazio, como explicado acima.

Exemplos Utilizando emoji:

fonte: https://google.com.br/imghp

Exemplos Utilizando frutas:

Imagem relacionada
fonte: https://google.com/imghp

Exemplos com a aplicação dos três métodos em conjunto:

const products = [{ id: 1, nome: 'prod 1'},
				{ id: 1, nome: 'prod 1'},
				{ id: 1, nome: 'prod 1'}]
				  
const purchaseRequests = [{ id: 10, idProd: 1, value: 10},
						{ id: 11, idProd: 3, value: 20},
						{ id: 12, idProd: 2, value: 40},
						{ id: 13, idProd: 3, value: 30}]

let arrayResponse = {}

const reducer = (accumulator, currentValue) => accumulator = currentValue

const calculate = (array, value) => {
	array.push(value)
	
	let totalValue = array.reduce(reducer)
	
	let priceAverage = totalValue / array.length
	
	return ([`amount : ${array.length}, priceAverage : ${priceAverage}, totalValue : ${totalValue}`])
}

const result = () => {
	try{
		products.map(value => {
			let values = [];
			(purchaseRequests.filter(request => {
				request.idProd === value.id
					? arrayResponse[request.idProd] = calculate(values,request.value)
					: 0					
				})
			)
		})
		return arrayResponse
	}catch(e){
		return e
	}
}

console.log(result())

/* { '1': ['amount : 1, priceAverage: 10, totalValue : 10'],
	'2': ['amount : 1, priceAverage: 40, totalValue : 40'],
	'3': ['amount : 2, priceAverage: 25, totalValue : 50']} */

Para finalizar deixo o exemplo acima, analise, tire suas próprias conclusões e até o próximo Post!