Skip to content

Latest commit

 

History

History
667 lines (546 loc) · 17.1 KB

File metadata and controls

667 lines (546 loc) · 17.1 KB

Clase 16

Monitorizar Variables Globales

    /**
    * Snippet Detectar variables globales
    * en Javascript por Carlos Benítez
    */
    (function( context ){
      var globals = { viewGlobals : true },
          startGlobals = [],
          newGlobals = [];

      for (var j in window) {
        globals[j] = true;
        startGlobals.push(j);
      }

      setInterval(function() {
        for ( var j in window ) {
          if ( !globals[j] ) {
            globals[j] = true;
            newGlobals.push(j);
            console.warn( 'New Global: ' + j + ' = ' + window[j] + '. Typeof: ' + (typeof window[j]) );
          }
        }
      }, 1000);

      context.viewGlobals = function(){
        console.groupCollapsed( 'View globals' );
          console.groupCollapsed( 'Initial globals' );
            console.log( startGlobals.sort().join( ",\n" ) );
          console.groupEnd();
          console.groupCollapsed( 'New globals' );
            console.warn( newGlobals.sort().join( ",\n" ) );
          console.groupEnd();
        console.groupEnd();
      };

    })(this);

Colas de Ejecución

    function write(t) {
      console.log(new Date + ' | ' +t);
    }

    var Queue = function() {
      this._tasks = [];
    };

    Queue.prototype.add = function(fn, scope) {
      this._tasks.push({
        fn: fn,
        scope: scope
      });
      return this;
    };

    Queue.prototype.process = function() {
      var proxy, self = this;

      task = this._tasks.shift();

      if(!task) {
        return;
      }

      proxy = {
        end: function() {
          self.process();
        }
      };

      task.fn.call(task.scope, proxy);

      return this;    
    };

    Queue.prototype.clear = function() {
      this._tasks = [];

      return this;
    };

    var q = new Queue();

    // Tarea 1 (sincronica)
    q.add(function(proxy) {
      write('Tarea 1 (sincronica)');
      proxy.end();
    });

    // Tarea 2 (asincronica)
    q.add(function(proxy) {
      write('Tarea 2 (asincronica)');
      setTimeout(function() {
        proxy.end();        
      }, 2500);
    });

    // Tarea 3 (sincronica)
    q.add(function(proxy) {
      write('Tarea 3 (sincronica)');
      proxy.end();
    });

    // Tarea 4 (asincronica)
    q.add(function(proxy) {
      write('Tarea 4 (asincronica)');
      setTimeout(function() {
        proxy.end();        
      }, 2500);
    });

    // Tarea 5 (sincronica)
    q.add(function(proxy) {
      write('Tarea 5 (sincronica)');
      proxy.end();
    });

    q.process();

Callback Hell

-callback_humor

  • Callback Hell
    • Escalabilidad limitada
    • Problemas para gestionar errores
    • Anidaciones complejas
    obj.metodo1(data, function(data1) {  
        function(data1, function(data2) {
            obj.otroMetodo(data2, function(data3) {
                obj.otroMetodoMas(data3, function(data4) {
                    // más y más.....
                })
            })
        })
    })

Promesas

promises_ecma6

A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise’s eventual value or the reason why the promise cannot be fulfilled. From promisesaplus.com/

  • Estados:

    • Fulfilled – La acción en relación con la promesa se logró.
    • Rejected – La acción en relación con la promesa falló.
    • Pending – Pendiente, no se ha cumplido o rechazado aún.
    • Settled - Arreglada, se ha cumplido o se ha rechazado (resuelta).
  • En ECMA6:

  • Soporte en navegadores

    • Una promesa
        var cuentaPromesas = 0;
        var errorMode = false;
        function testPromesa() {
    
          var numPromesaActual = ++cuentaPromesas;
    
          console.warn("Promesa Asíncrona numero ("+numPromesaActual+") - Iniciada")
    
          var miPromesa = new Promise(
            function(resolve, reject) {       
    
              console.info("Promesa Asíncrona numero ("+numPromesaActual+") - Proceso asincrónico empezado");
    
              if(errorMode){
                  reject(numPromesaActual)
              } else{
                window.setTimeout(
                  function() {
                    resolve(numPromesaActual)
                  }, Math.random() * 2000 + 1000);
              }
            });
          miPromesa.then(
            function(val) {
              console.info("Promesa Asíncrona numero ("+val+") - Proceso asincrónico terminado");
              console.warn("Promesa Asíncrona numero ("+numPromesaActual+") - Finalizada");
            }).catch(
              function(val){
                console.error("Promesa Asíncrona numero ("+val+") - ERROR FATAL");
            });
        };
    
        testPromesa();
    • Usando .race()
        var p1 = new Promise(function(resolve, reject) {
            setTimeout(resolve, 500, "uno");
        });
        var p2 = new Promise(function(resolve, reject) {
            setTimeout(resolve, 100, "dos");
        });
    
        Promise.race([p1, p2]).then(function(value) {
          console.log(value); // "dos" - p2 más rápida
        });
    • Usando .all()
        var errorMode = false
    
        var p1 = new Promise(function(resolve, reject) {
          console.log("P1 - Iniciada");
          setTimeout(resolve, 1000, "P1 - Terminada");
        });
        var p2 = new Promise(function(resolve, reject) {
          console.log("P2 - Iniciada");
          setTimeout(resolve, 2000, "P2 - Terminada");
        });
        var p3 = new Promise(function(resolve, reject) {
          if(errorMode){
            reject("errorMode-Activado");
          } else {
            console.log("P3 - Iniciada");
            setTimeout(resolve, 3000, "P3 - Terminada");
          }
    
        });
        var p4 = new Promise(function(resolve, reject) {
          console.log("P4 - Iniciada");
          setTimeout(resolve, 4000, "P4 - Terminada");
        });
    
        Promise.all([p1, p2, p3, p4]).then(function(value) {
          console.info("Promise.all -> TODO TERMINADO", value)
        }, function(reason) {
          console.log("Parece... que fallamos!", reason)
        });
    • Usando Ajax
        function $http(url){
    
          var core = {
    
            ajax : function (method, url, args) {
    
              var promise = new Promise( function (resolve, reject) {
    
                var client = new XMLHttpRequest();
                var uri = url;
    
                if (args && (method === 'POST' || method === 'PUT')) {
                  uri += '?';
                  var argcount = 0;
                  for (var key in args) {
                    if (args.hasOwnProperty(key)) {
                      if (argcount++) {
                        uri += '&';
                      }
                      uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
                    }
                  }
                }
    
                client.open(method, uri);
                client.send();
    
                client.onload = function () {
                  if (this.status >= 200 && this.status < 300) {
                    resolve(this.response);
                  } else {
                    reject(this.statusText);
                  }
                };
                client.onerror = function () {
                  reject(this.statusText);
                };
              });
    
              return promise;
            }
          };
    
          // Patrón Adaptador
          return {
            'get' : function(args) {
              return core.ajax('GET', url, args);
            },
            'post' : function(args) {
              return core.ajax('POST', url, args);
            },
            'put' : function(args) {
              return core.ajax('PUT', url, args);
            },
            'delete' : function(args) {
              return core.ajax('DELETE', url, args);
            }
          };
        };
    
        var callback = {
          success : function(data){
             console.log(1, 'success', JSON.parse(data));
          },
          error : function(data){
             console.log(2, 'error', JSON.parse(data));
          }
        };
    
        // Prueba bicis
        $http("http://bicimad-api.herokuapp.com/api-v1/locations/")
          .get()
          .then(callback.success)
          .catch(callback.error);
    
        // Prueba bicis 2
        var bicisCerca = {
          url: 'http://bicimad-api.herokuapp.com/api-v1/locations/nearest/',
          lat: '40.418889',
          long: '-3.691944',
          distance: '1000000000'
        };
        var cercaMio = bicisCerca.url+"?lat="+bicisCerca.lat+"&long="+bicisCerca.long+"&distance="+bicisCerca.distance;
    
        $http(cercaMio)
          .get()
          .then(callback.success)
          .catch(callback.error);
  • Alternativas para usar promesas:

    • Q

          function primeraFuncion() {
              var deferred = Q.defer();
              setTimeout(function() {
                  console.info('Primera funcion');
                  deferred.resolve();
              }, 2000);
              return deferred.promise;
          }
      
          function segundaFuncion() {
              var deferred = Q.defer();
              setTimeout(function() {
                  console.info('Segunda funcion');
                  deferred.resolve();
              }, 1000);
              return deferred.promise;
          }
          Q()
              .then(primeraFuncion)
              .then(segundaFuncion)
              .done();        
    • RSVP.js

    • When.js

Require.js & AMD

Require & AMD logo

  • Asincronia Asincronia

  • Dependencias y modularidad Modularidad

Entendiendo la utilidad de Require.js

  • Código convencional (Código espagueti):

      <!doctype html>
    
      <html lang="en">
      <head>
        <meta charset="utf-8">
    
        <title>Testing Requirejs</title>
    
    
      </head>
    
      <body>
        <script src="calculadora.js"></script>
      </body>
      </html>
    • calculadora.js
    function sumar (x, y) {
        return x+y
    };
    
    function restar (x, y) {
        return x-y
    };
    
    function multiplicar (x, y) {
        return x*y
    };
    
    
    function dividir (x, y) {
        return x/y
    };
  • Código convencional (Creando un objeto):

    • calculadora.js
    var calculadora = {};
    
    calculadora.sumar = function (x,y) {
        return x + y
    };
    calculadora.restar = function (x, y) {
        return x - y
    }
    calculadora.multiplicar = function (x, y) {
        return x * y
    }
    calculadora.divir = function (x, y) {
        return x / y
    }
  • Código convencional (Mejorando la escalabilidad "dividiendo el objeto"):

    • index.html:
    <script src="sumar.js"></script>
    <script src="restar.js"></script>
    <script src="divir.js"></script>
    <script src="multiplicar.js"></script>
    • /sumar.js
    var calculadora = calculadora || {};
    calculadora.sumar = function (x,y) {
        return x + y
    };
    • /restar.js
    var calculadora = calculadora || {};
    calculadora.restar = function (x, y) {
        return x - y
    }
    • /dividir.js
    var calculadora = calculadora || {};
    calculadora.divir = function (x, y) {
        return x / y
    }
    • /multiplicar.js
    var calculadora = calculadora || {};
    calculadora.multiplicar = function (x, y) {
        return x * y
    }

Usando Require.js

  • AMD:

    <script data-main="calculadora" src="require.js"></script>
    • /calculadora.js
    require(['calculadora/sumar', 'calculadora/restar', 'calculadora/cuadrado'], function (sum, res, cua) {
      console.info(sum(1,2)); // 1 + 2
      console.info(res(3,1)); // 3 - 1
      console.log(cua(2)); // 2 * 2
    });
    • calculadora/sumar.js
    define(function () {
      return function (x, y) {
          return x + y;
      };
    });
    • calculadora/restar.js
    define(function () {
      return function (x, y) {
          return x - y;
      };
    });
    • calculadora/multiplicar.js
    define(function () {
      return function (x, y) {
          return x * y;
      };
    });
    • calculadora/cuadrado.js
    define(['calculadora/multiplicar'], function (multiplicar) {
      return function (x) {
          return multiplicar(x, x);
      };
    });

Require.js - Modo Avanzado

  • Require.js con dependencias externas:

    • vendor/jquery.min.js (en local)

    • script.js

    require(['vendor/jquery'], function($){
        $('#hola').html("<h1>HOLA! Hola!</h1>");
    });
  • Require.js varios modulos en el mismo archivo:

    • script.js
    require(['hola', 'adios'], function(hola, adios){
        $('#hola').html("<h1>"+hola+" y "+adios+"!</h1>");
    });
    • hola.js
    define(function() {
        return "Hola";
    });
    
    define('adios', function() {
        return "adios";
    });
  • Require.js configurando baseUrl:

    • Estructura del proyecto:
      www/
          /assets/
          /css/
          /js/
              /App/
                  main.js
          /vendor/
              bootstrap.js
              jquery.js
    
    • config.js:
    requirejs.config({
        baseUrl: '.assets/js'
    });
    • *.js
    require(['vendor/jquery', 'vendor/bootstrap', 'app/main']);
  • Require.js configurando Paths:

    • Estructura del proyecto:
      www/
          /assets/
          /css/
          /js/
              /app/
                  main.js
          /vendor/
              bootstrap.js
              jquery.js
    
    
    • config.js:
    requirejs.config({
        baseUrl: '.assets/js',
        paths: {
            'jquery': 'vendor/jquery',
            'bootstrap': 'vendor/bootstrap',
            'main': 'app/main'
        }
    });
    • *.js:
    require(['jquery', 'bootstrap', 'main']);

Más Patrones

Algoritmia

Ejercicios

1 - Aplicaremos algunos de los conceptos aprendidos para mejorar el cajero automático que creamos anteriormente.

  • Objetivos:

    • Desarrolla el HTML y CSS necesario. Ya no utilizaremos la consola.
    • Toda la interación seguirá la filosofía de la programación dirigida por eventos
    • Usa una función anónima autoejecutada para encapsular el código
    • Utiliza el return para gestionar los métodos y propiedades privadas
  • Opcional:

    • usar el patrón init-time branching para gestionar los eventos
  • Solución