2016-02-05 12 views
5

Próbuję zaimplementować funkcję odbicia, która działa z obietnicą w javascript. W ten sposób każdy rozmówca może spożywać wynik "oderwanej" funkcji za pomocą Obietnicy. Oto najlepiej udało mi się wymyślić do tej pory:Funkcja odbicia zaimplementowana z obietnicami

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; 
    }; 
} 

Idealnie chciałbym wdrożyć tę funkcję użytkową bez wprowadzając zależność EventEmitter (lub wykonawczych własną podstawową wersję EventEmitter) , ale nie mogę wymyślić, jak to zrobić. jakieś pomysły?

+0

jak jest 'debounce' funkcja będzie używana? – Aprillion

+0

Co to jest "wewnętrzny"? – thefourtheye

+0

@Apillion Jest on używany jako standardowa funkcja odbicia, podobnie jak funkcja odbicia dostarczona przez [lodash] (https://lodash.com/docs#debounce), z tym że chcę, aby wywołujący mieli dostęp do wartości zwracanej wewnętrznej funkcjonować poprzez obietnicę. Czy to jest odpowiedź na Twoje pytanie? Mogę rozwinąć dalej, jeśli nie. – Chris

Odpowiedz

12

znalazłem lepszy sposób zaimplementować to z obietnic:

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)); 
    }; 
} 

I nadal mile widziane sugestie, ale nowa realizacja odpowiada moje pierwotne pytanie o tym, jak wdrożyć tę funkcję bez uzależnienia od EventEmitter (lub coś podobnego to).

1

Nie ma pojęcia, co próbujesz osiągnąć, ponieważ w znacznym stopniu zależy od Twoich potrzeb. Poniżej znajduje się coś nieco ogólnego. Bez solidnego zrozumienia tego, co dzieje się w poniższym kodzie, naprawdę może nie chcieć tego użyć.

// 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)

Zobacz konsola, gdy uruchomiony powyższy kod. Włożyłem kilka wiadomości, żeby pokazać trochę o tym, co się dzieje. Najpierw pewna funkcja, która zwraca obietnicę, jest przekazywana jako argument do new debounce(). Spowoduje to utworzenie odfiltrowanej wersji funkcji.

Po uruchomieniu funkcji wyrzuconej w powyższym kodzie (a(1), a(2), and a(3)) zauważysz, że podczas przetwarzania zwraca tę samą obietnicę, zamiast uruchamiać nową. Gdy obietnica jest kompletna, usuwa starą obietnicę. W powyższym kodzie czekam na timeout ręcznie z setTimeout przed uruchomieniem (3).

Możesz usunąć obietnicę również w inny sposób, np. Dodając funkcję resetowania lub usuwania na debounce.prototype, aby usunąć obietnicę w innym czasie. Możesz także ustawić go na timeout. Testy w dzienniku konsoli powinny pokazywać, że p1 i p2 otrzymują tę samą obietnicę (porównanie porównania "===" jest prawdziwe) i że p3 jest inne.

0

Wylądowałem tutaj, ponieważ chciałem uzyskać wartość zwrotu z obietnicy, ale debounce w underscore.js powrócił undefined zamiast tego. Skończyło się na używaniu wersji lodash z wiodącym = true. Działa to w moim przypadku, ponieważ nie obchodzi mnie, czy wykonanie prowadzi lub kończy.

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

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