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.

Avatar for Jean Carlo Emer

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