2016-10-04 4 views
0

Ich versuche, eine asynchrone Authentifizierung Handler, die eine Implementierung mit einem Rückruf oder Versprechen haben kann. Der Umfang ist, diese Funktion zu umhüllen, um immer ein Versprechen zurückzugeben, also kann ich es weiteren Rückruf/Versprechen Agnostic verwenden.Machen Sie JavaScript-Funktion mit Callback/Versprechen Implementierung, immer ein Versprechen

Ich wäre sehr dankbar, wenn jemand Hilfe mit diesen Szenarien bieten könnte, ist eines der Beispiele das wirkliche Leben.

Was passiert, wenn die Funktion ist so etwas wie:

function getData(id, callback) { 
    var deferred = Q.defer(); 
    apiCall('/path/to/id', function (err, data) { 
    if (err) deferred.reject(new Error(err)); 
    //do something with data 
    deferred.resolve(processedData); 
    } 
    deferred.promise.nodeify(callback); 
    return deferred.promise; 
} 

und ich möchte die .fromCallback auf diese Weise

function myProcessedDataFunction(id) { 
    return Promise.fromCallback(function (callback) { 
    return getData(id, callback); 
    }, {multiArgs: true}); 
} 

Wird diese Arbeit benutzen? Wird myProcessedDataFunction eine korrekte Zusage zurückgeben?

Ein Beispiel aus der Praxis ist:

Ich habe einen Authentifizierungs-Handler, die möglicherweise oder möglicherweise nicht mit einer Callback-Funktion, und zur gleichen Zeit umgesetzt werden kann unter Verwendung Versprechen umgesetzt werden; oder es könnte einen Wahr/Falsch-Wert zurückgeben;

function authHandlerImplementation1(username, password) { 
    return (username === 'validUsername' && password === 'validPassword'); 
} 

function authHandlerImplementation2(username, password, callback) { 
    apiCall('/path/to/authorization', function (err, result) { 
    if (err) return callback(err, null); 
    callback(null, result); 
    }); 
} 

function authHandlerImplementation3(username, password) { 
    return new Promise(function (reject, resolve) { 
    apiCall('/path/to/authorization', function (err, result) { 
     if (err) return reject(err); 
     resove(result); 
    }); 
    }); 
} 

function authHandlerImplementation4(username, password, callback) { 
    var deferred = Q.defer(); 
    apiCall('/path/to/id', function (err, data) { 
    if (err) deferred.reject(new Error(err)); 
    //do something with data 
    deferred.resolve(processedData); 
    } 
    deferred.promise.nodeify(callback); 
    return deferred.promise; 
} 

Ich werde eine Bluebird-Implementierung für 5. versuchen.

function authHandlerImplementation5(username, password, callback) { 
    return apiCall('/path/to/id', callback).asCallback(callback); // I hope this is the right way to do it (correct me if I'm wrong, please) 
} 

und meine checkAuth Funktion verwendet die authHandler Implementierung und will Rückruf/Versprechen Agnostiker sein.

function checkAuth(username, password) { 
    var self = this; 
    return Promise.fromCallback(function(callback) { 
    return self.authHandler(username, password, callback); 
    }, {multiArgs: true}); 
} 

Falls die authHandlerImplementation Rückrufe nicht verwenden (nur einen Wert zurückgibt) (implementation1), die checkAuth hängt, nichts passiert, meine Tests fehlschlagen.

Gibt es irgendeine Bluebird-Methode, die jede Art von authHandler-Implementierung in ein Versprechen einbinden kann (sei es einfache Rückgabe-, Callback- oder Versprechensimplementierung)?

+1

Ich denke, es ist keine gute Idee, versprechen und Callback-Stil Funktionen thos Weg zu mischen. Ich denke, es ist viel besser, bei einem zu bleiben und die Funktionen beim Eintritt in die bevorzugte umzuwandeln. Der Grund ist, dass es unmöglich ist zu entscheiden, ob eine Funktion Callbacks verwendet oder nicht. Was passiert, wenn 'authHandler' synchron ist und sofort undefined zurückgibt? Und übrigens, bluebird 'fromCallback' funktioniert nur mit Callback-Style-Funktionen. –

+2

Ich empfehle Ihnen, entweder Callbacks oder Versprechen zu wählen (hoffentlich letzteres), nicht beides. Beide zu unterstützen, ist hier unordentlich und auf der Aufrufseite. Ein Typ, an dem ich arbeite, hat ziemlich viel Code geschrieben, der beide Methoden unterstützt, und er wurde zur Wartungshölle. Ersetzen Sie es durch eine Just-Versprechungen-Implementierung halbiert die LoC und machte den Code viel einfacher zu verstehen. – Bojangles

+0

Ich verstehe Ihre Position und stimme der Einfachheit halber einer der Varianten zu. Auf der anderen Seite möchte ich dem Endbenutzer die Freiheit geben, beides zu verwenden. Ich versuche damit nicht einen Implementierungsstil zu erzwingen. @TamasHegedus Eine der zugrunde liegenden Fragen lautet wie Sie gesagt haben: Wie können Sie herausfinden, ob eine Funktion einen Rückruf oder ein Versprechen oder keine von beiden verwendet? Ich habe jetzt herausgefunden, dass '' 'fromCallback'''' '' only''' für Funktionen ist, die mit einem Callback implementiert werden. Ich dachte, es stünde auch die Funktion des Versprechens. Wenn es eine Möglichkeit gibt, dies zu tun, bitte beraten! –

Antwort

2

Nein, Bluebird hat kein solches Dienstprogramm. Das Unterstützen von Callbacks und Versprechungen ist nett, wenn Sie sie als API bereitstellen, nicht aber wenn Sie eine API konsumieren müssen. Sie unterscheiden, ob die Methode Callbacks oder Retourenversprechen oder beides von außen nicht akzeptiert und Code dynamisch ausgibt (bei jedem Anruf) könnte möglich sein, aber peinlich.

Drossel tut ein Dienstprogramm, die Funktion wickelt, die vielleicht zurückkehren, werfen oder ein Versprechen zurückzukehren, ist es Promise.method genannt (und es gibt auch Promise.try die sofort sie aufruft).

Ich würde empfehlen, Ihre Anrufer Versprechen zu verwenden, wenn sie einen asynchronen Auth-Handler übergeben möchten. Wenn sie nur eine Callback-basierte haben, können sie sie dennoch in Promise.promisify selbst verpacken, bevor sie Ihnen zur Verfügung gestellt werden.

0

Ich habe ein paar Sachen ausprobiert und es geschafft, dass es funktioniert. Ich werde im Folgenden detaillierte Informationen zu den Methoden geben, die ich versucht habe. Das Szenario ist für eine json-rpc 2.0-Serverimplementierung vorgesehen, die eine authHandler-Funktionsimplementierung zum Überprüfen der Gültigkeit der bereitgestellten Anmeldeinformationen in einer Anforderung empfängt.

Aktualisierung:
Verwendung von Versprechen.Methode auf dem AuthHandler
var promisifiedAuthHandler = Promise.method(self.authHandler); funktioniert für die synchrone Implementierung des AuthHandler.
Fehler bei der Callback-Implementierung.

Verwenden von Promise.promisify auf dem authHandler, der in die Promise.method eingebunden ist, funktioniert für die Callback-Implementierung
var promisifiedAuthHandler = Promise.promisify(Promise.method(self.authHandler));.
Fehler bei der synchronen Implementierung.

Die Bereitstellung eines Callbacks für den authHandler (auch wenn er nicht in der Implementierung verwendet wird) funktioniert für alle Methoden. Es geht so (für einen allgemeinen Fall zu schreiben, und dies ist Teil eines Moduls mit ES5-Class node module geschrieben):

function _checkAuth(req) { 
    var self = this; 
    var credentials = self._getCredentials(req); 
    var promisifiedAuthHandler = Promise.method(self.authHandler); // for the sync implementation 

    switch (authType) { 
    // general case, let's say, there are several types 
    // will just write one as an example. 
    case Authorization.WHATEVERTYPE: 
    return promisifiedAuthHandler(credentials, function callback(err, result) { 
     if (err) return Promise.reject(err); 
     return Promise.resolve(result); 
    } 
    } 
} 

und dem server.enableCookie/JWT/BasicAuth-Handler kann in den genannten drei Arten implementiert werden: sync/Rückruf/Versprechen; Wie folgt:

server.enableCookieAuth(function (cookie) { 
    return (cookie === validCookieValue); 
}); 

server.enableCookieAuth(function (cookie, callback) { 
    apiCall('path/to/auth', function(err, result) { 
    // apiCall could have a promise implementation, as well, and could 
    // be used with .then/.catch, but this is not that important here, since we care 
    // about the handler implementation) 
    if (err) return callback(err, null); 
    callback(null, result); // can be returned 
    } 
}); 

server.enableCookieAuth(function (cookie) { 
    // let's write the apiCall with promise handling, since we mentioned it above 
    return apiCall('path/to/auth').then(function (result) { 
    return Promise.resolve(result); 
    }).catch(function (err) { 
    return Promise.reject(err); 
    }); 
}); 

Jetzt können wir unsere _checkAuth Funktion intern nur mit Versprechungen, agnostisch der authHandler Funktion Implementierung verwenden. Wie in:

handleHttp: function(req, res) { 
    var self = this; 
    // ...other processing 
    self._checkAuth(req).then(function (result) { 
    // check if the user is authed or not 
    if (result) { 
     // further process the request 
    } else { 
     // handle unauthorized request 
    } 
    }).catch(function (err) { 
    // handle internal server or api call (or whatever) error 
    }); 
} 

Der Trick war, unseren Rückruf mit einer Versprechen Implementierung zu schreiben. Wir stellen dem authHandler immer eine Callback-Implementierung zur Verfügung, auch wenn der authHandler sie nicht verwendet. Auf diese Weise stellen wir immer sicher, dass die Auth-Handler-Implementierung ein Versprechen zurückgibt, wenn sie eine Callback-Implementierung verwendet.

Alle Kommentare sind willkommen und ich würde gerne einige Meinungen zu diesem Thema hören!

Vielen Dank für Ihre schnelle Antworten!

Verwandte Themen