Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Controle de fluxo com execução assíncrona

Controle de fluxo com execução assíncrona

A teoria e os desafios por trás do controle de fluxo: Callbacks, Promises e Promises com Generators analisados de forma prática e crítica. De um lado a mais importante linguagem da Internet e seu ecossistema e do outro os principais desafios do desenvolvimento assíncrono.

Jean Carlo Emer

May 17, 2014
Tweet

More Decks by Jean Carlo Emer

Other Decks in Technology

Transcript

  1. var  size          =  20;   var

     canvas      =  createCanvas(container);   ! for  (var  edge  =  0;  edge  <  edges;  edge++)  {          var  angle  =  Math.PI  *  edge  /  (edges  /  2);          var  range  =  createRange(centerRadius);          range.addCanvas(canvas,  edge);          range.init();   }   ! canvas.init();   Range.events();
  2. if  (condition);   ! switch  (expression)  {}   ! for

     ([before];  [condition];  [afterEach]);   ! while  (condition);   ! for  (variable  in  object);   ! try  {}  catch  (e)  {} ... e funções
  3. Contador externo que permite condicionar a execução de código para

    o futuro. TIMERS setTimeout(callback,  3000);
  4. Executa o download de um arquivo e ser informado do

    seu conteúdo no futuro. XML HTTP REQUEST var  req  =  new  XMLHttpRequest();   req.open('GET',  url);   req.onload  =  callback;
  5. Monitora eventos e executa código com base em uma interação

    do usuário ou mudança de estado. DOM EVENTS el.addEventListener('click',                                              callback);
  6. Monitora a árvore do DOM e executa código com base

    em suas mudanças. MUTATION OBSERVER new  MutationObserver(callback);
  7. Estabelecem uma conexão permanente com o servidor para envio e

    recebimento de dados. WEB SOCKETS var  ws  =  new  WebSocket('ws://addr');   ws.onmessage  =  callback;
  8. Estabelecem uma conexão permanente com o servidor para recebimento de

    dados. SERVER SENT EVENTS var  source  =  new  EventSource('addr');   source.onmessage  =  callback;
  9. Executam uma porção de código em uma thread separada da

    principal. WEBWORKERS var  worker  =  new  Worker('addr.js');   worker.onmessage  =  callback;
  10. Envio de mensagens entre diferentes documentos. WEB MESSAGES window.addEventListener('message',  

                                                   callback);
  11. As APIs emitem um evento para indicar que o código

    da callback deve ser executado.
  12. Tudo é executado em paralelo, exceto o seu código. -

    MIKITO TAKADA http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop
  13. SETTIMEOUT Define um timer nulo que tão logo agenda uma

    tarefa na fila de eventos. ASSÍNCRONO COM * setTimeout(callback,  0);
  14. If nesting level is greater than 5, [...], then increase

    timeout to 4. - WHATWG TIMER SPEC http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers
  15. SETIMMEDIATE Determina que uma tarefa seja colocada no fim da

    fila do laço. ASSÍNCRONO COM adeus aos timers setImmediate(callback); https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html
  16. Suportada apenas no IE10* e node.js mas com alguns polyfills:

    • postMessage e MessageChannel • <script> onreadystatechange • MutationObserver [*] IE10 bug - https://github.com/cujojs/when/issues/197 SETIMMEDIATE ASSÍNCRONO COM adeus aos timers
  17. WEBWORKERS Código executando num ambiente separado: worker. Resultados são passados

    para o navegador através de callbacks. multithreads ASSÍNCRONO COM
  18. WEBWORKERS Para garantir ausência de concorrência, os workers não tem

    acesso a página ou variáveis globais. Possuem acesso a XHR request, timers e a importação de scripts. multithreads ASSÍNCRONO COM
  19. try  {      document.addEventListener('click',  ()  =>  {    

         //  ...          throw  new  Error('o/');      });   }  catch  (error)  {      handleError(error);   } X Tratamento de erros
  20. document.addEventListener('click',  ()  =>  {      //  ...    

     handleError('o/');   }); aproveite as closures
  21. $.get('products',  (products)  =>  {      products.forEach((product)  =>  {  

           var  element  =  $('<a>').text(product.name);          element.on('click',  (event)  =>  {         var  url  =  'products/'  +  product.id;              $.get(url,  (product)  =>  {                  //  ...              });          });            //  ...      });   }); X Callback hell
  22. class  ProductsFactory  {      fetch()  {      

       $.get('products',  this.onSync.bind(this));      }      onSync(data)  {          products.forEach((item)  =>  {              var  product  =  new  Product(item).render();              //  ...          });      }   } http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them
  23. class  Product  {      constructor(data)  {      

       this.data  =  data;          this.element  =  $('<a>');      }      render()  {          this.element.text(data.name);          return  this;      }      //  ...   } organize! http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them
  24. var products; ! $.get('products', function (data) { products = data;

    }); não há nada que uma global não resolva X
  25. $.get('gifts',  function  (data)  {      if  ($.active  ===  0)

     {            this_is_my_callback();      }   });   ! ! $.get('products',  function  (data)  {      if  ($.active  ===  0)  {            this_is_my_callback();      }   }); número de 
 requisições abertas X
  26. var  products  =  get('products');   ! products.then(function  onFulfilled()  {  

       //  succeeded   },  function  onRejected()  {      //  error   }); retorna uma promise
  27. var  products  =  get('products');   ! products.then(function  onFulfilled()  {  

       //  succeeded   },  function  onRejected()  {      //  error   }); quando ou se já 
 tiver um valor...
  28. setTimeout(function  ()  {     products.then(function  ()  {    

       //  ...     });   },  9999); não tem como perder o bonde!
  29. var  products  =  get('products');   ! var  basket  =  new

     Basket(products);   var  list      =  new  ProductsList(products); argumento
  30. new  Promise(function  (resolve,  reject)  {        if  (Math.random()

     >  .5)  {              resolve('success');        }  else  {              reject('fail');        }   }
  31. new  Promise(function  (resolve,  reject)  {        if  (Math.random()

     >  .5)  {              resolve('success');        }  else  {              reject('fail');        }   } sucesso
  32. new  Promise(function  (resolve,  reject)  {        if  (Math.random()

     >  .5)  {              resolve('success');        }  else  {              reject('fail');        }   } falha
  33. function  get(url)  {      return  new  Promise(function  (resolve,  reject)

     {          var  req  =  new  XMLHttpRequest();          req.open('GET',  url);   !        req.onload  =  function  ()  {              if  (req.status  ==  200)  {                  resolve(req.response);              }  else  {                  reject(Error(req.statusText));              }          };                    req.send();      });   } http://www.html5rocks.com/en/tutorials/es6/promises
  34. function  get(url)  {      return  new  Promise(function  (resolve,  reject)

     {          var  req  =  new  XMLHttpRequest();          req.open('GET',  url);   !        req.onload  =  function  ()  {              if  (req.status  ==  200)  {                  resolve(req.response);              }  else  {                  reject(Error(req.statusText));              }          };                    req.send();      });   } http://www.html5rocks.com/en/tutorials/es6/promises operação assíncrona
  35. function  get(url)  {      return  new  Promise(function  (resolve,  reject)

     {          var  req  =  new  XMLHttpRequest();          req.open('GET',  url);   !        req.onload  =  function  ()  {              if  (req.status  ==  200)  {                  resolve(req.response);              }  else  {                  reject(Error(req.statusText));              }          };                    req.send();      });   } http://www.html5rocks.com/en/tutorials/es6/promises sucesso
  36. function  get(url)  {      return  new  Promise(function  (resolve,  reject)

     {          var  req  =  new  XMLHttpRequest();          req.open('GET',  url);   !        req.onload  =  function  ()  {              if  (req.status  ==  200)  {                  resolve(req.response);              }  else  {                  reject(Error(req.statusText));              }          };                    req.send();      });   } http://www.html5rocks.com/en/tutorials/es6/promises falha
  37. $.get('test.php').then(      function()  {          alert('$.get

     succeeded');      },  function()  {          alert('$.get  failed!');      }   ); jQuery entende* promises * aguarde, falaremos mais a respeito
  38. parser.start()      .then(function  ()  {        return

     getFiles();     })     .then(function  ()  {       //  ...     });
  39. parser.start()      .then(function  ()  {        return

     getFiles();     })     .then(function  ()  {       //  ...     }); espera por getFiles
  40. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); cria uma promise 
 resolvida
  41. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); 1º BLOCO
  42. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); ... resolvida
  43. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); rejeita a 
 promise
  44. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); 2º BLOCO
  45. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); resolvida?
  46. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); "tratamento"
  47. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); sucesso!! nenhum 
 erro emitido
  48. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); 3º BLOCO
  49. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); resolvida?
  50. Promise.resolve('Yep')      .then(function(data)  {          throw

     new  Error(data);      },  function  (error)  {          //  nothing  wrong  with  Yep      })      .then(null,  function  (error)  {          console.error(error);      })      .then(function  ()  {          console.log('I  am  fine');      }); termina aqui
  51. $.get('gifts',  function  (data)  {      if  ($.active  ===  0)

     {            this_is_my_callback();      }   });   ! ! $.get('products',  function  (data)  {      if  ($.active  ===  0)  {            this_is_my_callback();      }   }); X
  52. Promise.all([      get('gifts'),        get('products')   ])

         .then(function  (results)  {          //  results[0]  -­‐>  gifts          //  results[1]  -­‐>  products      },  function  (result)  {          //  first  rejected      }); array de promises
  53. Promise.all([      get('gifts'),        get('products')   ])

         .then(function  (results)  {          //  results[0]  -­‐>  gifts          //  results[1]  -­‐>  products      },  function  (result)  {          //  first  rejected      }); todas resolvidas ou primeira 
 rejeitada
  54. Promise.race([      get('gifts'),        get('products')   ])

         .then(function  (results)  {          //  first  resolved      },  function  (result)  {          //  first  rejected      }); uma corrida?!
  55. Promise.race([      get('gifts'),        get('products')   ])

         .then(function  (results)  {          //  first  resolved      },  function  (result)  {          //  or  first  rejected      }); primeiro 
 que terminar
  56. Nosso exemplos foram todos seguindo a especificação de Promises/A+. Algumas

    implementações: • when, Q, RSVP, ... • ES6 Promises COMO USAR https://github.com/jakearchibald/es6-promise
  57. • Excessões nas callbacks quebram a execução de código •

    Não permite chaining (1.8-) com then e sim com pipe. A IMPLEMENTAÇÃO e suas inconsistências DA JQUERY Promise.resolve(
    $.get('products'));
  58. function*  infinite()  {      var  i  =  0;  

       while  (true)  {          yield  i++;      }   }   ! var  iterator  =  infinite();   iterator.next().value;   iterator.next().value; indicativo de generator
  59. function*  infinite()  {      var  i  =  0;  

       while  (true)  {          yield  i++;      }   }   ! var  iterator  =  infinite();   iterator.next().value;   iterator.next().value; apenas inicia
  60. function*  infinite()  {      var  i  =  0;  

       while  (true)  {          yield  i++;      }   }   ! var  iterator  =  infinite();   iterator.next().value;   iterator.next().value; pega o i++ 
 do yield
  61. function*  infinite()  {      var  i  =  0;  

       while  (true)  {          yield  i++;      }   }   ! var  iterator  =  infinite();   iterator.next().value;   iterator.next().value; executa o laço
 outra vez
  62. https://github.com/visionmedia/co co(function  *(){      var  products  =  yield  get('products');

         var  gifts        =  yield  get('gifts');      console.log(products[0]);      console.log(gifts[0]);   })();
  63. co(function  *(){      var  products  =  yield  get('products');  

       var  gifts        =  yield  get('gifts');      console.log(products[0]);      console.log(gifts[0]);   })(); https://github.com/visionmedia/co ao resolver a 
 primeira...
  64. argumentos passados para o then https://github.com/visionmedia/co co(function  *(){    

     var  products  =  yield  get('products');      var  gifts        =  yield  get('gifts');      console.log(products[0]);      console.log(gifts[0]);   })();
  65. https://github.com/visionmedia/co co(function  *(){      var  getProducts  =  get('products');  

       var  getGifts        =  get('gifts');   !    var  products        =  yield  getProducts;      var  gifts              =  yield  getGifts;            console.log(products[0]);      console.log(gifts[0]);   })(); paralelismo!
  66. [Promises] give you an abstraction that lets you model problems

    at a higher level. - JAMES COGLAN https://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-
 promises-are-functional-nodes-biggest-missed-opportunity
  67. Promises mean having enough memory to keep data around. -

    DREW CRAWFORD http://sealedabstract.com/code/broken-promises Haters gonna hate. - 1º COMENTÁRIO