No se recomienda utilizar variables externas para bloquear o modificar el estado de los botones debido a las siguientes dificultades:
- Requiere comprender las diferencias entre eventos success, complete, error y timeout, y registrar los correctos; un error haría que la funcionalidad dejara de estar disponible
- Inevitablemente requiere registrar un evento complete adicional comparado con el flujo normal
- El código de restauración del estado fácilmente se mezcla con código no relacionado
Se recomiendan métodos de consulta activa del estado (A, B, usando jQuery como ejemplo) o funciones utilitarias (C, D) para eliminar operaciones duplicadas:
A. Envío Exclusivo
Solo permite una operación de envío simultánea, y hasta que se complete no se permite otra.
modulo.enviar = function() {
if (this.promesa_.state() === 'pending') {
return
}
return this.promesa_ = $.post('/api/guardar')
}
B. Envío Codicioso
Envíos ilimitados donde solo cuenta la última operación; se debe proporcionra retroalimentación inmediata de la última operación, siendo irrelevantes los resultados anteriores.
modulo.enviar = function() {
if (this.promesa_.state() === 'pending') {
this.promesa_.abort()
}
// implementación
}
Ejemplo: botones de "me gusta"/"no me gusta" donde la retroalimentación inmediata mejora la experiencia de usuario y reduce la carga del servidor.
C. Envío Controlado
El intervalo entre dos envíos válidos siempre será mayor o igual a un tiempo específico; envía a frecuencia constante.
modulo.enviar = throttling(150, function() {
// implementación
})
Si el cliente envía 10 peticiones cada 100ms, este módulo solo procesará 6 (cada una separada por 150ms). Útil para eventos como resize, scroll o mousemove.
D. Envío Perezoso
Requiere que el intervalo entre envíos sea mayor a un tiempo específico para que sean válidos.
modulo.enviar = debounce(150, function() {
// implementación
})
Ejemplo: guardado automático en editores que ignora pulsaciones rápidas consecutivas.
E. Envío con Memoria
var rastrear = memoizar(function(url) {
return $.post('/rastreador', { 'url': url })
})
Para los mismos parámetros, siempre retorna resultados idénticos. Ejemplo: editor que obtiene información de enlaces sin repetir peticiones para URLs idénticas.
F. Envío Acumulativo
var solicitud = crearPila(5, function() {
$.post('/', { lista: JSON.stringify([].slice.call(arguments)) })
})
// Envío consecutivo
solicitud({b:1}), solicitud({b:2}), solicitud({b:3}), solicitud({b:4}), solicitud({b:5})
/* POST =>
lista:[{"b":1},{"b":2},{"b":3},{"b":4},{"b":5}]
*/
Implemnetación de ejemplo:
var crearPila = function(cantidad, alFiltrar, alValor) {
var valores = [], id = function(valor) { return valor }
return function(valor) {
valores.push((alValor || id).apply(this, arguments))
if (valores.length === cantidad) {
alFiltrar.apply(this, valores)
valores = []
}
}
}
G. Envío Muestreado
cargadoAuto.escuchar(fuentes, 'siguiente', muestrear(3, function() {
this.activar()
}))
Si muestrear es una función de selección fija (elige 1 de n), funciona así:
O-O-X-O-O-X
Para aplicaciones de carga automática que requieren (dos automáticas, una manual):
X-X-O-X-X-O
Se puede definir una función de selección configurable:
opciones { muestrear: (n) => n % 3 !== 0 }
Después de cada carga, de cada tres intentos, dos activarán carga automática.