backbone js – Timer de tiempo variable o dinámico

febrero 28, 2014

timer

timer


En una aplicación web necesitaba mostrar una pantalla diferente cada cierto tiempo, una que se mostrará 10 minutos y otra 1 minuto. En javascript existen 2 métodos para hacer esto: setInterval y setTimeout. El primer método ejecuta una función cada cierto tiempo, pero ese tiempo no es variable. La segunda ejecuta la función una sola vez después del período de tiempo que le indicamos.

Decidí utilizar setTimeout e intenté hacer lo siguiente

app.Router = Backbone.Router.extend({
    routes: {
        "": "home"
    },
initialize: function(){
    this.$content = $('#content')
    app.views.audiencias = new app.views.Audiencias({model: new app.models.AudienciaCollection()})
    app.views.screensaver = new app.views.Screensaver()
    this.activeView = 'audiencias'
},

home: function(){
    var view = this.activeView === 'audiencias' ? app.views.audiencias : app.views.screensaver
    view.setElement(this.$content).render()
    var duration = this.activeView === 'audiencias' ? 1000*60*10 : 1000*60*1
    this.activeView = this.activeView === 'audiencias' ? 'screensaver' : 'audiencias'
    setTimeout(this.home, duration) //ejecutamos recursivamente este método en el tiempo determinado
}
})

El problema es que sólo se ejecutaba 2 veces, al cargar la página y al transcurrir el primer timeout. Esto debido al contexto de la palabra clave ‘this’. Este problema tiene varias soluciones.

Una de ellas es utilizar el método ‘bind()’ (a partir de la version 1.8.5 de javascript) de la siguiente manera

setTimeout(this.home.bind(this), duration)

La otra es extender las funciones setTimeout y setInterval para poder llamarlas mediante el método ‘call’ con el contexto correcto

// Enable the passage of the 'this' object through the JavaScript timers
 
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval;
 
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeST__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
 
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeSI__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};

y llamarla de la siguiente manera

setTimeout.call(this, this.home, duration)

Fuentes:
https://developer.mozilla.org/en-US/docs/Web/API/window.setTimeout#A_possible_solution
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Function_context
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#With_setTimeout

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: