Me pidieron que creara un objeto llamado foo que pudiera encadenar el log funciones y wait .
Por ejemplo:
foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner'); En este escenario, primero imprime el breakfast , espera 3 segundos, imprime el lunch y luego, después de 3 segundos, imprime la dinner .
Intenté algo como esto, pero no funciona. ¿Qué me perdí?
var foo = { log: function(text){ console.log(text); return foo; }, wait: function(time) { setTimeout(function() { return foo; }, time); } } foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner');Siempre es mejor usar promesas. Una implementación de esta funcionalidad podría ser;
class Foo { constructor(){ this.promise = Promise.resolve(); } log(txt){ this.promise = this.promise.then(_ => console.log(txt)) return this; } wait(ms){ this.promise = this.promise.then(_ => new Promise(v => setTimeout(v,ms))); return this; } } var foo = new Foo(); foo.log("happy").wait(1000).log("new").wait(1000).log("year");Coloque la llamada a wait dentro de la anterior, y como último elemento, como una función recursiva.
meals=['breakfast','elevenses','lunch','afternoon tea','dinner','supper']; c=0; wait=t=>{setTimeout(function() { if (c<meals.length) document.write(meals[c++],'<br>');wait(500); }, t);} wait(500);Para que conste, la excelente respuesta de Redu sin el azúcar de clase .
const foo = { promise: Promise.resolve(), log(txt) { this.promise.then(_ => console.log(txt)); return this; }, wait(ms) { this.promise = this.promise.then(_ => new Promise(v => setTimeout(v, ms))); return this; } }; // OR const Foo = (defaultMs = 1000) => { let promised = Promise.resolve(); return { log(txt) { promised.then(_ => console.log(txt)); return this; }, wait: function(ms) { promised = promised.then( _=> new Promise( rs => setTimeout(rs, ms || defaultMs) ) ); return this; } }; }; foo.log("Happy").wait(1000).log("new").wait(1000).log("year"); Foo().wait(3000) .log(`** From Foo ;)`).log(`Happy`).wait().log("new").wait().log("year");Más corto, dentro de Promise (no recomendado).
Promise.prototype.log = function(txt) { return this.then(() => console.log(txt)) } Promise.prototype.wait = function(ms) { return this.then(() => new Promise(res => setTimeout(res, ms))) } var foo = Promise.resolve() foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner')Puedes hacerlo sin promesas:
const foo = { log(text) { return {...foo, start: () => { this.start(); console.log(text); }}; }, wait(time) { return {...foo, start: () => { setTimeout(this.start, time); }}; }, start() {} }; foo.log('breakfast').wait(3000).log('lunch').wait(3000).log('dinner').start();foo.log() y foo.wait() regresan inmediatamente, devolviendo un clon modificado de foo . Se crea un clon usando {...foo} , pero con la función start() modificada para que llame a this.start() de la persona que llama seguido de la nueva operación. Cuando la cadena está completa, llama a start() para iniciar las acciones.Me inspiré en la solución de @James, que es parcialmente incorrecta porque los mensajes de registro están en el orden inverso, pero él no usa Promise s. Sigo pensando que la solución de @Redu debería ser la aceptada (después de todo, si puedes usar Promise s, eso es perfecto), pero esta también es interesante en mi opinión:
const foo1 = { incrementalTimeout: 0, nextActions: [], log(text) { const textLog = () => { console.log(text); }; if (this.incrementalTimeout == 0) textLog(); else this.nextActions.push(textLog); return this; }, wait(time) { let newObj = {...this, incrementalTimeout: this.incrementalTimeout + time, nextActions: []}; setTimeout(() => { newObj.nextActions.forEach((action) => action()); } , newObj.incrementalTimeout); return newObj; } } foo1.log('breakfast').wait(1000).log('lunch').wait(3000).log('dinner'); La idea es que no registre el text de inmediato, sino que push una lambda con console.log en una matriz que se llamará después de que expire el tiempo de espera correcto.
Ejecuto todas las operaciones de log y wait una tras otra, pero llevo un registro de los segundos de espera antes de ejecutar las acciones. Cada vez que se llama a una nueva wait , el tiempo de espera incrementalTimeout se incrementa en time . Para mantener separadas las nextActions que pertenecen a diferentes períodos de tiempo, devuelvo un newObj cada vez, más o menos como lo hace @James.