Opóźnianie powrotu funkcji asynchronicznej w REPL

Jeśli podczas korzystania z REPL ( http://nodejs.org/api/repl.html ) używamy funkcji asynchronicznej możemy trafić na mały problem. Funkcja wywoływana z REPL po zakończeniu swojego działania i zwróceniu wartości jest uznawana za całkowicie wykonaną i zostaje odblokowana możliwość wprowadzania nowych poleceń. W przypadku funkcji asynchronicznej może dochodzić do dziwnych sytuacji kiedy to funkcja zwróci swój wynik użytkownik zdążył już coś wprowadzić i wszystko się rozjeżdża. Co jeśli chcemy aby REPL poczekał do zakończenia działania funkcji asynchronicznej i zwrócenia wartości ? Nie jest to takie łatwe standardowo nie dostajemy żadnej możliwości kontrolowania co się dzieje ( callbacka etc. ) jednak przychodzi nam z pomocą możliwość definiowania własnej funkcji wykonywanej przy każdym wykonaniu polecenia.
repl.start(options)
jedna z opcji to
eval - function that will be used to eval each given line. Defaults to an async wrapper for eval(). See below for an example of a custom eval.
Przykład
function eval(cmd, context, filename, callback) {
callback(null, result);
}
Ostatni argument to callback który powinnien być wykonany kiedy chcemy aby REPL przywrócił możliwość wprowadzania poleceń. Napisałem małą klasę która pozwoli w łatwy sposób to wszystko kontrolować
var AsynchronousHandle = new function (){
this._callback = null;
this._mutexBlock = false;

this.setCallback = function( callback ){
this._callback = callback;
}

this.runCallback = function( result ){
this._callback( null , result == undefined ? null : result );
}

this.handleEval = function( cmd, context, filename, callback ){
this.unblockMutex();
this.setCallback( callback );

eval( cmd );

if( !this.mutexIsBlocked() ){
this.runCallback( null );
}
}

this.blockMutex = function(){
this._mutexBlock = true;
}

this.unblockMutex = function(){
this._mutexBlock = false;
}

this.mutexIsBlocked = function(){
return this._mutexBlock;
}
}
Przykład użycia
require( 'repl' ).start( {
useColors: true,
input: process.stdin,
output: process.stdout,
eval: AsynchronousHandle.handleEval.bind( AsynchronousHandle )
});

function testFunction(){
AsynchronousHandle.blockMutex();

console.log( 'testFunction' );

setTimeout( AsynchronousHandle.runCallback.bind( AsynchronousHandle ) , 1000 );
}
Metody klasy
  • setCallback – ustawia callback który zostanie wywołany
  • runCallback – uruchamia callback
  • handleEval – metoda która obsługuje nowy eval podawany opcjach startowania REPL
  • blockMutex – blokuje mutex
  • unblockMutex – odblokowuje mutext
Sposób użycia Jest to w sumie bardzo proste podczas startowania REPL jako eval podajemy metode handleEval z klasy AsynchronousHandle np.
require( 'repl' ).start( {
useColors: true,
input: process.stdin,
output: process.stdout,
eval: AsynchronousHandle.handleEval.bind( AsynchronousHandle )
});
Potem kiedy funkcja asynchroniczna zaczyna być wywoływana blokujemy mutext
AsynchronousHandle.blockMutex()
Kiedy wszystko zostanie już wykonane i zwrócone uruchamiamy runCallback z AsynchronousHandle np.
AsynchronousHandle.runCallback.bind( AsynchronousHandle )
podczas wykonywania runCallback możemy podać w 1 parametrze co funkcja zwróci ale nie musimy tego robić w tym przypadku zwróci null

Dodaj komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.