A natureza de thread único do JavaScript/Typescript: programação assíncrona

Jan 20 2023
No meu primeiro artigo, escrevi sobre algumas das diferenças entre JS e TS. Agora vamos explorar a natureza assíncrona como uma única linguagem encadeada.

No meu primeiro artigo , escrevi sobre algumas das diferenças entre JS e TS.

Agora vamos explorar a natureza assíncrona como uma única linguagem encadeada.

Em JavaScript e TypeScript, a natureza de thread único significa que apenas uma tarefa pode ser executada em um determinado momento.

Por outro lado, a programação assíncrona refere-se à capacidade da linguagem de executar tarefas de forma assíncrona, permitindo que o thread principal de execução continue em execução enquanto aguarda a conclusão de outras tarefas. Isso é obtido por meio do uso de retornos de chamada , eventos , promessas e async / await .

Antes de começar a explicar isso em termos de codificação, gostaria de falar sobre uma referência muito interessante de como as tarefas assíncronas de uma linguagem de thread único são muito semelhantes ao nosso cérebro quando tentamos fazer multitarefas .

Nesta seção irei resumir um longo texto/capítulo escrito por Kyle Simpson em seu livro “You Dont Know Javascript” sobre a conexão do Cérebro Sequencial com a assincronização. Se você estiver interessado apenas na parte de codificação de como funciona, pode pular esta parte.

“ Tenho certeza de que a maioria de vocês já ouviu alguém dizer (até mesmo fez essa afirmação): “ Sou multitarefa. ”
Mas somos multitarefas? Podemos realmente fazer duas ações conscientes e intencionais ao mesmo tempo e pensar/raciocinar sobre ambas exatamente ao mesmo tempo? Nosso nível mais alto de funcionalidade cerebral tem multithreading paralelo acontecendo?

A resposta pode surpreendê-lo: provavelmente não.

Não é assim que nossos cérebros parecem ser configurados. Somos muito mais tarefas individuais do que muitos de nós gostaríamos de admitir. Na verdade, só podemos pensar em uma coisa a qualquer momento.

Não estou falando de todas as nossas funções cerebrais automáticas, subconscientes e involuntárias, como batimentos cardíacos, respiração e piscar de olhos. Todas essas são tarefas vitais para nossa vida sustentada, mas não alocamos intencionalmente nenhum poder cerebral para elas.”

De acordo com Simpson, os humanos não são capazes de realizar multitarefas da mesma forma que um computador. Embora seja verdade que o cérebro humano pode processar várias tarefas simultaneamente, ele não é capaz de dar atenção igual a todas as tarefas ao mesmo tempo. Em vez disso, alternamos rapidamente nossa atenção entre as tarefas, da mesma forma que um único programa encadeado pode executar apenas uma tarefa por vez.

Felizmente, enquanto ficamos obcecados em verificar feeds de redes sociais pela 15ª vez em três minutos, nosso cérebro continua em segundo plano (threads!) Com todas essas tarefas importantes.

Quando fingimos ser multitarefas, como tentar digitar algo ao mesmo tempo em que conversamos com um amigo ou familiar ao telefone, o que mais provavelmente estamos fazendo é agir como alternadores rápidos de contexto . Em outras palavras, alternamos entre duas ou mais tarefas em rápida sucessão, progredindo simultaneamente em cada tarefa em pequenos e rápidos blocos. Fazemos isso tão rápido que para o mundo exterior parece que estamos fazendo essas coisas em paralelo.

Isso soa como simultaneidade de eventos assíncronos (assim como o que acontece no JS) para você?!

Há uma grande diferença observável entre como planejamos várias tarefas e como nossos cérebros realmente operam essas tarefas.
Embora em um nível operacional nossos cérebros sejam eventos assíncronos, parece que planejamos tarefas de maneira sequencial e síncrona. “Preciso ir ao mercado, depois comprar um pouco de leite e deixar minha roupa na lavanderia.”

Você pode realmente imaginar ter uma linha de pensamento que planeja suas tarefas como esta:

“ Preciso ir na loja (1), mas no caminho tenho certeza que vou receber uma ligação (2) , então 'Oi, mamãe', e enquanto ela começa a falar, eu fico olhando o endereço da loja (3) no GPS, mas vai demorar um segundo para carregar, então vou desligar o rádio (4) para ouvir melhor a mamãe...
aí eu vou perceber que esqueci de colocar uma jaqueta ( 5) e está frio lá fora, mas não importa, continue dirigindo e conversando com a mamãe …
e então o ding do cinto de segurança me lembra de colocar o cinto de segurança (6) , então 'Sim, mamãe, estou usando meu cinto de segurança, sempre coloco!'. Ah, finalmente:

o GPS tem as direções, agora…”

Por mais ridículo que pareça como uma formulação de como planejamos nosso dia e pensamos sobre o que fazer e em que ordem, é exatamente como nossos cérebros operam em um nível funcional. Mas lembre-se, isso não é multitarefa, é apenas uma troca rápida de contexto.

Com isso em mente, vamos dar uma olhada em como a programação assíncrona funciona em JavaScript.

Agora vamos codificar :

Existem várias maneiras de realizar programação assíncrona em JavaScript/Typescript, como mencionei no início deste artigo, inclusive usando: Callbacks , Events, Promises, Async/Await.

  • Um retorno de chamada é uma função que é passada como um argumento para outra função e é executada após a conclusão da função externa. Por exemplo:
  • function greet(name, callback) {
      console.log(`Hello, ${name}!`);
      callback();
    }
    
    function sayGoodbye() {
      console.log("Goodbye!");
    }
    
    greet("John", sayGoodbye);
    // Output: "Hello, John!"
    // Output: "Goodbye!"
    

  • Um evento é um sinal de que algo aconteceu e um ouvinte é uma função executada em resposta a esse evento. Por exemplo:
  • const button = document.querySelector("button");
    
    button.addEventListener("click", () => {
      console.log("Button was clicked!");
    });
    

  • Uma promessa representa o resultado de uma operação assíncrona e pode ser resolvida (com êxito) ou rejeitada (com falha), assim como as promessas da vida real; quando você faz uma promessa, você a cumpre (resolve) ou não (rejeita).
    As promessas podem ser usadas para simplificar o processo de encadeamento de operações assíncronas. Por exemplo:
  • const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("Completed Async Task");
      }, 1000);
    });
    
    promise.then((result) => {
      console.log(result);
    });
    // Output: "Async task completed" (after 1 second)
    

  • Async/await: um recurso do JavaScript que permite o uso da sintaxe async/await para fazer com que o código assíncrono pareça e se comporte como código sincronizado. Async/await é construído sobre promessas e torna mais fácil trabalhar com código assíncrono.
  • async function greet(name) {
      return `Hello, ${name}!`;
    }
    
    async function main() {
      const greeting = await greet("John");
      console.log(greeting);
    }
    
    main();
    // Output: "Hello, John!"
    

No geral, a programação assíncrona permite a execução de várias tarefas, mantendo a natureza de thread único da linguagem. Ele permite um programa mais responsivo e eficiente, permitindo que o thread principal continue em execução enquanto aguarda a conclusão de outras tarefas.

Se você gosta deste conteúdo não hesite em seguir. Existem muitos outros projetos em mãos sobre os quais pretendo escrever em um futuro próximo. Até então,

Obrigado por ler!