Ao estudar o Javascript, deparei-me com vários artigos sobre funções e operações assíncronas várias vezes. Apesar das vantagens indubitáveis de tal funcionalidade, cada vez que eu era levada a dificuldades pela listagem citada pelos autores. As palavras mudaram, a essência permaneceu a mesma, mingau estava fervendo na minha cabeça. Sob o corte - um pequeno guia para o desenvolvimento histórico e versões do ECMA.
Por que precisamos de operações assíncronas?
Um programa de computador pode executar um número ilimitado de tarefas. Não é segredo que aplicativos da Web devem trabalhar com muitas tarefas diferentes, que geralmente precisam usar os mesmos dados. Em particular, um dos exemplos mais comuns é exibir informações do usuário (UI) e recuperar informações usando solicitações do servidor. Não é de surpreender que quase todos os desenvolvedores da Web enfrentem isso: trabalhando com um determinado banco de dados, fornecendo uma interface de usuário, organizando alguma API - tudo isso está literalmente em todas as tarefas de teste, não apenas dos programadores de JS.
Por que não executar comandos sequencialmente?Frequentemente, as informações necessárias ao usuário podem ser obtidas somente após um período de tempo considerável. Se você organizar o programa como:
- Obtendo informações do site https: / some / api / item / 1
- Exibe informações sobre o primeiro item na tela.
sérias dificuldades surgirão com a renderização da página e a criação de uma impressão agradável no usuário (a chamada experiência do usuário). Imagine: uma página, digamos, Netflix ou Aliexpress, terá que obter dados de centenas de bancos de dados antes de começar a exibir o conteúdo para o usuário. Esse atraso será semelhante ao carregamento de um nível de jogo em 3D e, se o jogador estiver pronto para esperar, o usuário do site deseja obter o máximo de informações no momento.
A solução foi encontrada:
operações assíncronas . Enquanto o segmento principal do programa está ocupado inicializando e exibindo elementos do site na tela, ele também envia tarefas para os outros segmentos no espírito de "
obter os produtos para o usuário ". Assim que esse segmento conclui seu trabalho, as informações "se estabelecem" no segmento principal e ficam disponíveis para exibição, e na própria página da web existe um determinado espaço reservado - um objeto que ocupa espaço para informações futuras.

Nesse momento, a página já é exibida, apesar de algumas solicitações ainda não terem sido aprovadas.

Provavelmente, em algum lugar na parte inferior da página, mais algumas solicitações retornam um valor, e a página continua sendo atualizada e renderizada dinamicamente, sem nenhum inconveniente para o usuário.
ES5 e versões anteriores: retorno de chamada
Antes de prosseguir com a revisão dos retornos de chamada, vamos dar uma olhada / descobrir quais são as
funções de uma ordem superior .
Uma função de ordem superior em JS é uma
função que assume outra função como argumento . Aqui está um exemplo:
objectIsString(objectRef) { return typeof(objectRef) === 'String'; } listOfObjects.filter(objectIsString);
Assim, a função objectIsString foi passada para a função de ordem superior - filter - que permite filtrar listOfObjects e deixar apenas objetos do tipo string na lista.
Os retornos de chamada funcionam de maneira semelhante. Esta é uma função passada como argumento para outra função. Na maioria das vezes, a função setTimeout é usada como exemplo de uma função que processa retornos de chamada. Em geral, é usado como setTimeout (função, timeoutValue), em que função é uma função de retorno de chamada executada pelo navegador após um período especificado no tempo limite.
setTimeout(console.log(1), 2000); console.log(2);
Imprimir 2 1.
ES 6: Promessas
No Padrão 6, um novo tipo foi introduzido - Promise (promessa, a seguir - Promise). Uma promessa é um tipo cujos objetos têm um dos três estados: pendentes, cumpridos, rejeitados. Além disso, com os dois últimos estados, você pode "associar" funções - retornos de chamada. Assim que o processo assíncrono descrito na estrutura da promessa em si for bem-sucedido / fracassado, a função associada a ela será chamada. Esse processo é chamado de "retornos de chamada suspensos e é executado usando os métodos then e catch da própria promessa. A diferença é que, quando você chama os argumentos, duas funções são transferidas - em caso de sucesso (onFullfillment) e falha (onRejected), enquanto catch aceita, como não é difícil adivinhar, apenas uma função para processar erros em uma promessa. Para determinar se uma promessa foi executada com sucesso em um caso específico, bem como para parametrizar o resultado retornado
Vamos criar e usar uma promessa em etapas.
Agora adicione manipuladores de eventos usando o método then. O argumento para a função que lida com o sucesso é resultado, enquanto o argumento para a função para lidar com a falha da promessa é erro.
promise .then( result => { }, error => { } );
Feito!
Então, descreveremos mais uma vez o processo de criação de uma promessa brevemente:
- Inicializar o objeto (nova promessa)
- Passamos a função de resolver e / ou rejeitamos como o único argumento para o construtor. Uma função deve ter pelo menos 1 operação assíncrona
- Usando os métodos then / catch, adicionamos funções - manipuladores de resultados.
Geradores. Rendimento
Também no padrão ES6, um novo tipo de função foi definido - geradores. Essas funções têm a capacidade de retornar valores diferentes várias vezes com chamadas idênticas à primeira vista. Vamos ver como eles fazem isso e por que usá-lo.
A forma padrão do gerador: function * functionName () {}. No corpo das próprias funções, a palavra rendimento é usada para retornar um valor intermediário.
Como exemplo, considere o seguinte gerador:
function* generateNumber() { yield 1; yield 2; return 3; }
No momento, o gerador está no início de sua execução. Cada vez que o próximo método gerador é chamado, o código descrito antes do rendimento (ou retorno) mais próximo será executado, e o valor indicado na linha com uma dessas palavras também será retornado.
Let one = generateNumber.next();
A próxima chamada retornará o valor 2. Da mesma maneira, a terceira retornará o valor 3 e encerrará a execução da função.
Let two = generateNumber.next();
Apesar disso, o gerador ainda pode ser acessado através da
próxima função. No entanto, ele retornará o mesmo valor: o objeto {done: true}.
ES7 Assíncrono / aguardar
Juntamente com o desejo de agradar os amantes de OOP com a ajuda de classes de açúcar sintáticas e imitação de herança, os criadores do ES7 estão tentando facilitar a compreensão do javascript e para os amantes escreverem código síncrono. Usando construções assíncronas / aguardadas, o usuário pode escrever código assíncrono o mais semelhante possível ao síncrono. Se desejar, você pode se livrar das promessas recentemente estudadas e reescrever o código com o mínimo de alterações.
Considere um exemplo:
Usando promessas:
requestBook(id) { return bookAPIHelper.getBook(id).then(book => {console.log(book)}); }
Usando assíncrono / espera.
async requestBook(id) { Const book = await bookAPIHelper.getBook(id); Console.log(book); }
Vamos descrever o que vimos:
1) Async - palavra-chave adicionada ao declarar uma função assíncrona
2) Aguardar - uma palavra-chave adicionada ao chamar uma função assíncrona.
ES8. Iteração Assíncrona
A iteração de dados de forma síncrona tornou-se possível no ES5. Após duas especificações, decidiu-se adicionar a possibilidade de iteração assíncrona trabalhar em fontes de dados assíncronas. Agora, quando next () for chamado, ele retornará não {value, done}, mas uma promessa (consulte ES6).
Vejamos a função createAsyncIterable (iterável).
async function* createAsyncIterable(iterable) { for (const elem of iterable) { yield elem; } }
Como você pode ver, a função inicializa a coleção, para cada chamada para os elementos dos quais uma promessa será retornada com o valor especificado em iterável.
const asyncIterable = createAsyncIterable(['async 1', 'async 2']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); asyncIterator.next() .then(result => { console.log(result);
Além disso, o novo padrão define um loop de espera a ser conveniente para essas operações.
for await (const x of createAsyncIterable(['a', 'b']))
TL; DR
Não é necessário saber e lembrar de cor a qual versão do ECMAScript esta ou aquela sintaxe pertence, especialmente se você acabou de iniciar seu conhecimento do comportamento assíncrono em JS. Ao mesmo tempo, estudar a assincronia exatamente na ordem proposta pelo histórico de desenvolvimento de especificações permitirá ao programador não apenas entender perfeitamente a sintaxe e as instruções passadas ao mecanismo JS, mas também seguir a lógica de melhorar o ECMAScript como um produto, entender as tendências ditadas pelos desenvolvedores de JS, separá-las e aceitar .
Em suma, então:
Retornos de chamada <= ES5
Promessas, Rendimento (Geradores): ES6
Assíncrono / aguardar: ES7
Iteradores assíncronos: ES8