2016-02-05 13 views
5

Ich versuche, eine Debounce-Funktion zu implementieren, die mit einem Versprechen in Javascript funktioniert. Auf diese Weise kann jeder Anrufer das Ergebnis der entprellten Funktion mit Hilfe eines Versprechens konsumieren. Hier ist das Beste, was ich in der Lage gewesen, um mit so weit:Debounce-Funktion mit Versprechen implementiert

function debounce(inner, ms = 0) { 
    let timer = null; 
    let promise = null; 
    const events = new EventEmitter(); // do I really need this? 

    return function (...args) { 
    if (timer == null) { 
     promise = new Promise(resolve => { 
     events.once('done', resolve); 
     }); 
    } else { 
     clearTimeout(timer); 
    } 

    timer = setTimeout(() => { 
     events.emit('done', inner(...args)); 
     timer = null; 
    }, ms); 

    return promise; 
    }; 
} 

Idealerweise möchte ich an dieser Nutzenfunktion implementieren ohne auf EventEmitter eine Abhängigkeit der Einführung (oder meine eigene Basisversion EventEmitter Umsetzung) , aber ich kann mir keinen Weg dazu vorstellen. Irgendwelche Gedanken?

+0

wie wird 'debounce' Funktion verwendet werden, zu gehen? – Aprillion

+0

Was ist "inner"? – thefourtheye

+0

@Aprillion Es wird als Standardentprellfunktion verwendet, wie die Entprellfunktion von [lodash] (https://lodash.com/docs#debounce), außer dass die Anrufer Zugriff auf den Rückgabewert des inneren haben sollen Funktion über ein Versprechen. Beantwortet das deine Frage? Ich kann weiter ausholen, wenn nicht. – Chris

Antwort

12

fand ich einen besseren Weg, dies mit dem Versprechen umzusetzen:

function debounce(inner, ms = 0) { 
    let timer = null; 
    let resolves = []; 

    return function (...args) {  
    // Run the function after a certain amount of time 
    clearTimeout(timer); 
    timer = setTimeout(() => { 
     // Get the result of the inner function, then apply it to the resolve function of 
     // each promise that has been created since the last time the inner function was run 
     let result = inner(...args); 
     resolves.forEach(r => r(result)); 
     resolves = []; 
    }, ms); 

    return new Promise(r => resolves.push(r)); 
    }; 
} 

Ich begrüße Vorschläge nach wie vor, aber die neue Implementierung beantwortet meine ursprüngliche Frage, wie ohne eine Abhängigkeit von EventEmitter diese Funktion zu implementieren (oder so ähnlich es).

1

Keine Ahnung, was Sie versuchen zu erreichen, da es sehr davon abhängt, was Ihre Bedürfnisse sind. Unten ist etwas etwas Generisches. Ohne einen soliden Überblick darüber, was in dem unten stehenden Code vor sich geht, möchten Sie ihn wirklich nicht verwenden.

// Debounce state constructor 
 
function debounce(f) { 
 
    this._f = f; 
 
    return this.run.bind(this) 
 
} 
 

 
// Debounce execution function 
 
debounce.prototype.run = function() { 
 
    console.log('before check'); 
 
    if (this._promise) 
 
    return this._promise; 
 
    console.log('after check'); 
 
    return this._promise = this._f(arguments).then(function(r) { 
 
    console.log('clearing'); 
 
    delete this._promise; // remove deletion to prevent new execution (or remove after timeout?) 
 
    return r; 
 
    }.bind(this)).catch(function(r) { 
 
    console.log('clearing after rejection'); 
 
    delete this._promise; // Remove deletion here for as needed as noted above 
 
    return Promise.reject(r); // rethrow rejection 
 
    }) 
 
} 
 

 
// Some function which returns a promise needing debouncing 
 
function test(str) { 
 
    return new Promise(function(resolve, reject) { 
 
    setTimeout(function() { 
 
     console.log('test' + str); 
 
     resolve(); 
 
    }, 1000); 
 
    }); 
 
} 
 

 
a = new debounce(test); // Create debounced version of function 
 
console.log("p1: ", p1 = a(1)); 
 
console.log("p2: ", p2 = a(2)); 
 
console.log("p1 = p2", p1 === p2); 
 
setTimeout(function() { 
 
    console.log("p3: ", p3 = a(3)); 
 
    console.log("p1 = p3 ", p1 === p3, " - p2 = p3 ", p2 === p3); 
 
}, 2100)

Ansicht der Konsole, wenn sie über den Code ausgeführt wird. Ich stelle ein paar Nachrichten, um ein bisschen darüber zu zeigen, was vor sich geht. Zuerst wird eine Funktion, die ein Versprechen zurückgibt, als Argument an new debounce() übergeben. Dies erstellt eine entprellte Version der Funktion.

Wenn Sie die entprellte Funktion wie der obige Code() ausführen, werden Sie während der Verarbeitung bemerken, dass die gleiche Versprechen zurückgibt, anstatt eine neue zu starten. Sobald das Versprechen abgeschlossen ist, entfernt es das alte Versprechen. Im obigen Code warte ich manuell mit setTimeout auf das Timeout, bevor ich a (3) starte.

Sie können das Versprechen auch auf andere Weise löschen, z. B. durch Hinzufügen oder Löschen einer Funktion auf debounce.prototype, um das Versprechen zu einem anderen Zeitpunkt zu löschen. Sie könnten es auch auf Timeout setzen. Die Tests im Konsolenprotokoll sollten zeigen, dass p1 und p2 das gleiche Versprechen erhalten (Referenzvergleich "===" ist wahr) und dass p3 anders ist.

0

Ich bin hier gelandet, weil ich den Rückgabewert des Versprechens erhalten wollte, aber entbündeln Sie in underscore.js gab stattdessen zurück. Ich endete mit lodash Version mit leading = true. Es funktioniert für meinen Fall, weil es mir egal ist, ob die Ausführung vor- oder nacheilt.

https://lodash.com/docs/4.17.4#debounce

_.debounce(somethingThatReturnsAPromise, 300, { 
    'leading': true, 
    'trailing': false 
})