Programação Assíncrona em JavaScript - do básico ao avançado

Programação Assíncrona em JavaScript - do básico ao avançado

Estamos acostumados a programar utilizando um fluxo de execução síncrono. Porém, nos dias de hoje, programar em JavaScript contempla inúmeras operações assíncronas. Desde um simples timer utilizando setTimeOut, passando por respostas a eventos do DOM ou requisições assíncronas AJAX até operações de I/O como a escrita de um arquivo. A compreensão e domínio da programação assíncrona é essencial para o desenvolvedor JavaScript moderno. Nesta palestra serão apresentados inúmeros conceitos e exemplos relacionados a programação assíncrona. Falaremos sobre fluxo de execução de um programa, programação assíncrona, callbacks e closures, promises, generators e funções async.

52711e2157a6fed933b0361cc06a6953?s=128

Marcel dos Santos

July 19, 2019
Tweet

Transcript

  1. Marcel Gonçalves dos Santos @marcelgsantos programação assíncrona em JavaScript do

    básico ao avançado
  2. pensandonaweb.com.br desenvolvedor web full-stack Marcel Gonçalves dos Santos @marcelgsantos

  3. None
  4. @femugsp sp.femug.com

  5. @phpsp phpsp.org.br

  6. Interaja nas mídias sociais!
 
 - fale sobre o evento,

    palestrantes e conteúdo - tire fotos do evento e publique
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes
  7. 1. seguir @marcelgsantos no Twitter
 2. tuitar utilizando as hashtags

    #TheDevConf, #TrilhaJavaScript e #Async
 3. não vale tuíte em branco e retuíte
 4. ler e preencher este simples formulário
 bit.ly/sorteio-tdc-sp-2 Concorra a um livro da Casa do Código!
  8. Fluxo de execução de um programa

  9. o fluxo de execução de um programa é determinado pela

    ordem em que suas instruções são executadas
  10. normalmente é sequencial e segue a ordem em que as

    instruções aparecem no código
  11. existem diversas instruções para guiar o fluxo de execução como

    if, else, for, while, try…catch entre outras
  12. !// execution flow 
 let val1 = prompt('Input the first

    value:'); let val2 = prompt('Input the second value:'); val1 = parseInt(val1); val2 = parseInt(val2); if ((val1 !>= 1 !&& val1 !<=10) !&& (val2!>= 1 !&& val2 !<=10)) { let result = sum(val1, val2); console.log('The result is %d.', result); } else { console.log('There was a problem during the calculation.'); }
  13. o JavaScript possui um fluxo único de execução que ocorre

    na thread principal
  14. a thread principal é compartilhada entre a renderização da página

    e códigos JavaScript
  15. em JavaScript um fluxo de execução pode ser síncrono ou

    assíncrono
  16. Fluxos síncronos e assíncronos

  17. um código é síncrono quando uma instrução é executada somente

    quando a instrução anterior estiver terminado
  18. !// synchronous code
 let val1 = prompt('Input the first value:');

    let val2 = prompt('Input the second value:'); val1 = parseInt(val1); val2 = parseInt(val2); if ((val1 !>= 1 !&& val1 !<=10) !&& (val2!>= 1 !&& val2 !<=10)) { let result = sum(val1, val2); console.log('The result is %d.', result); } else { console.log('There was a problem during the calculation.'); }
  19. um código síncrono é simples de entender e fácil de

    ler
  20. um código é assíncrono quando as instruções podem ser executadas

    sem ordem definida
  21. um código assíncrono é complicado de entender e difícil de

    ler
  22. !// asynchronous code fs.readFile('lorem.txt', {encoding: 'utf8'}, function(err, text) { if

    (err) { console.log('Houston, we have a problem!'); return; }
 console.log(text); !// [2] Lorem ipsum dolor sit amet!!... }); console.log('Finished'); !// [1] Finished
  23. porém, um código assíncrono permite que o seu programa tenha

    um melhor desempenho
  24. Código bloqueante e não-bloqueante

  25. um código bloqueante é aquele que bloqueia a execução de

    uma instrução até que a instrução anterior seja finalizada
  26. o conceito foi inventado para tornar a programação mais fácil

  27. o espirro é algo bloqueante, ou seja, paramos “tudo” o

    que estamos fazendo quando vamos espirrar!
  28. um código não-bloqueante é aquele que não bloqueia a execução

    de uma instrução com base em uma instrução anterior não finalizada
  29. o ser humano é multitarefa e pode andar, falar e

    comer ao mesmo tempo, ou seja, são tarefas não-bloqueantes
  30. o hardware de um computador funciona de forma não-bloqueante e

    assíncrona
  31. é a linguagem que adiciona a semântica bloqueante e síncrona

  32. None
  33. perde-se muitos ciclos de CPU quando se espera disco e

    rede
  34. esse é o motivo pelo qual o hardware é assíncrono

  35. queremos a CPU rodando na capacidade máxima

  36. ou seja, assíncrono e não-bloqueante possui melhor desempenho

  37. Programação orientada à eventos
 event-driven programming

  38. pode-se utilizar eventos para implementar assincronicidade

  39. o Node.js abstrai as operações de I/O utilizando eventos

  40. o JavaScript é executado em um única thread, ela é

    conhecida como main thread ou thread principal
  41. porém threads auxiliares são utilizadas para outras operações

  42. utiliza-se eventos para sincronizar as tarefas entre a main-thread e

    as threads auxiliares
  43. Como utilizar a programação assíncrona
 em JavaScript

  44. existem vários padrões de programação assíncrona em JavaScript

  45. eventos
 
 pode-se receber resultados de computação assíncrona utilizando eventos

  46. eventos
 
 para isso deve-se registrar manipuladores de eventos ou

    event handler para um objeto
  47. var request = new XMLHttpRequest(); request.open('GET', 'https:!//swapi.co/api/people/1/'); request.onload = function()

    { !// add event handler if (request.status !== 200) { console.log(JSON.parse(request.response)); } else { console.log('error:', request.statusText); } }; request.onerror = function() { !// add event handler console.log('request error'); } request.send(); !// add request to task queue console.log('finish script');
  48. var request = new XMLHttpRequest(); request.open('GET', 'https:!//swapi.co/api/people/1/'); request.onload = function()

    { !// add event handler if (request.status !== 200) { console.log(JSON.parse(request.response)); } else { console.log('error:', request.statusText); } }; request.onerror = function() { !// add event handler console.log('request error'); } request.send(); !// add request to task queue console.log('finish script');
  49. var request = new XMLHttpRequest(); request.open('GET', 'https:!//swapi.co/api/people/1/'); request.onload = function()

    { !// add event handler if (request.status !== 200) { console.log(JSON.parse(request.response)); } else { console.log('error:', request.statusText); } }; request.onerror = function() { !// add event handler console.log('request error'); } request.send(); !// add request to task queue console.log('finish script');
  50. var request = new XMLHttpRequest(); request.open('GET', 'https:!//swapi.co/api/people/1/'); request.onload = function()

    { !// add event handler if (request.status !== 200) { console.log(JSON.parse(request.response)); } else { console.log('error:', request.statusText); } }; request.onerror = function() { !// add event handler console.log('request error'); } request.send(); !// add request to task queue console.log('finish script');
  51. ao utilizar um objeto XMLHttpRequest deve- se chamar explicitamente o

    método send() para adicionar a requisição na fila de tarefas
  52. contudo, existem APIs que não é necessário fazer isso de

    forma explícita
  53. callbacks
 
 os callbacks são porções de código (normalmente funções)

    que são executados em um tempo no futuro
  54. callbacks
 
 sempre quando uma tarefa assíncrona entra em ação,

    o callback é registrado e espera por uma mensagem para ser executado
  55. callbacks
 
 existe um loop de eventos que aguarda por

    mensagens
  56. callbacks
 
 as funções de callback que possuem acesso às

    variáveis do escopo em que foram definidas são chamadas de closures
  57. !// callback example
 
 console.log('Before setTimeout'); !// [1] setTimeout(() !=>

    { console.log('Callback added to the task queue executed!’); !// [3] }, 1000); !// after 1s the callback is added to the task queue console.log('After setTimeout'); !// [2]
  58. !// callback example (2)
 
 console.log('Before setTimeout'); !// [1] setTimeout(()

    !=> { console.log('Callback added to the task queue executed!’); !// [?] }, 0); console.log('After setTimeout'); !// [?]
  59. None
  60. callbacks
 
 uma das limitações de se utilizar callbacks é

    o callback hell
  61. !// callback hell module.asyncFunction((response1) !=> { response1.asyncFunction((response2) !=> { response2.asyncFunction((response3)

    !=> { response3.asyncFunction((response4) !=> { return response4; }); }); }); });
  62. promises
 
 elas são uma alternativa para callbacks para entregar

    resultados de uma computação assíncrona
  63. promises
 
 uma promise representa o possível 
 resultado de

    uma operação assíncrona
  64. !// promise (result of a request using fetch) const req

    = fetch('https:!//httpbin.org/delay/3'); console.log(req); 
 
 !// Promise {status: "pending", value: undefined}
  65. promises
 
 utiliza-se a função then() para atribuir funções de

    callback para promises
  66. promises
 
 e as funções de callback podem ser encadeadas

  67. !// using then to resolve a promise fetch('https:!//httpbin.org/ip') .then(response !=>

    response.json()) .then(result !=> console.log(result));
 !// {origin: "187.182.22.229, 187.182.22.229"}
  68. promises
 
 uma promise pode estar em três estados: pending,

    fulfilled ou rejected
  69. promises
 
 se uma promise não está mais pending, ela

    está settled
  70. !// create a promise (resolved) const promise = new Promise(function

    (resolve, reject) { if (true) { resolve('This promise was resolved.'); } else { reject('This promise was rejected!'); } }); promise.then(result !=> console.log(result)); 
 !// This promise was resolved.
  71. !// creating a promise (rejected) const promise = new Promise(function

    (resolve, reject) { if (false) { resolve('This promise was resolved.'); } else { reject('This promise was rejected!'); } }); promise.then( result !=> console.log(result), error !=> console.error(error) ); !// This promise was rejected!
  72. / creating a promise (rejected) const promise = new Promise(function

    (resolve, reject) { if (false) { resolve('This promise was resolved.'); } else { reject('This promise was rejected!'); } }); promise .then(result !=> console.log(result)) .catch(error !=> console.error(error)); 
 !// This promise was rejected!
  73. promises
 
 utiliza-se a função Promise.all() para receber uma notificação

    quando todas as promises forem resolvidas
  74. !// notify when all promises were fulfilled (after 5s) Promise.all([

    fetch('https:!//httpbin.org/delay/5'), fetch('https:!//httpbin.org/delay/3'), ]).then(result !=> console.log('Ok!', result)); !// Ok! (2) [Response, Response]
  75. promises
 
 utiliza-se a função Promise.race() para retornar a primeira

    promise de uma lista que foi resolvida ou rejeitada
  76. async e await
 
 é uma forma mais moderna de

    se receber resultados de computação assíncrona
  77. !// using async and await async function getCharacter(id) { const

    res = await fetch(`https:!//swapi.co/api/people/${id}/`); const data = await res.json(); return data; } getCharacter(1) .then(luke !=> console.log(luke)); !// {name: "Luke Skywalker", height: "172", …}
  78. async e await
 
 funciona seguindo a especificação de promises

  79. async e await
 
 a palavra-chave async é utiliza no

    início da função para indicar que ela será assíncrona
  80. async e await
 
 a palavra-chave await informa o código

    para esperar a promise ser resolvida antes de continuar a execução
  81. async e await
 
 a palavra-chave await só pode ser

    utilizado em funções com async
  82. async e await
 
 possui suporte na maioria dos navegadores

    modernos e no Node.js
  83. async e await
 
 torna o código mais simples de

    ler e mais fácil de depurar
  84. Conclusão

  85. o JavaScript possui uma natureza assíncrona e é importante compreendê-la

    bem
  86. a utilização de código assíncrono é essencial para desempenho

  87. Referências

  88. bit.ly/referencias-palestra-async

  89. Avalie!

  90. bit.ly/avalie-palestra-async

  91. @marcelgsantos speakerdeck.com/marcelgsantos Obrigado. Perguntas?