Ich habe mich gefragt, was der beste Ansatz für die Konfiguration eines Modulexports ist. "async.function" im folgenden Beispiel kann eine FS- oder HTTP-Anforderung sein, die aus Gründen des Beispiels vereinfacht wurde:
Hier ist ein Beispielcode (asynmodule.js):
var foo = "bar"
async.function(function(response) {
foo = "foobar";
// module.exports = foo; // having the export here breaks the app: foo is always undefined.
});
// having the export here results in working code, but without the variable being set.
module.exports = foo;
Wie kann ich das Modul erst exportieren, wenn der asynchrone Rückruf ausgeführt wurde?
Bearbeiten Sie eine kurze Anmerkung zu meinem tatsächlichen Anwendungsfall: Ich schreibe ein Modul zum Konfigurieren von nconf ( https://github.com/flatiron/nconf ) in einem Rückruf von fs.exists () (dh es analysiert eine Konfigurationsdatei und nconf einrichten).
node.js
asynchronous
Brett
quelle
quelle
require
die Abhängigkeit asynchron laden. Ich denke das ist mit babel formatierer möglich. Ich denke jedoch keine gute Lösung für diese. :(Antworten:
Ihr Export kann nicht funktionieren, da er sich außerhalb der Funktion befindet, während sich die
foo
Deklaration innerhalb befindet. Wenn Sie den Export jedoch in das Modul einfügen, können Sie nicht sicher sein, ob der Export definiert wurde.Der beste Weg, um mit einem Ansync-System zu arbeiten, ist die Verwendung eines Rückrufs. Sie müssen eine Rückrufzuweisungsmethode exportieren, um den Rückruf zu erhalten, und ihn bei der asynchronen Ausführung aufrufen.
Beispiel:
var foo, callback; async.function(function(response) { foo = "foobar"; if( typeof callback == 'function' ){ callback(foo); } }); module.exports = function(cb){ if(typeof foo != 'undefined'){ cb(foo); // If foo is already define, I don't wait. } else { callback = cb; } }
Hier
async.function
ist nur ein Platzhalter, um einen asynchronen Aufruf zu symbolisieren.In der Hauptsache
var fooMod = require('./foo.js'); fooMod(function(foo){ //Here code using foo; });
Mehrfacher Rückrufweg
Wenn Ihr Modul mehrmals aufgerufen werden muss, müssen Sie ein Array von Rückrufen verwalten:
var foo, callbackList = []; async.function(function(response) { foo = "foobar"; // You can use all other form of array walk. for(var i = 0; i < callbackList.length; i++){ callbackList[i](foo) } }); module.exports = function(cb){ if(typeof foo != 'undefined'){ cb(foo); // If foo is already define, I don't wait. } else { callback.push(cb); } }
Hier
async.function
ist nur ein Platzhalter, um einen asynchronen Aufruf zu symbolisieren.In der Hauptsache
var fooMod = require('./foo.js'); fooMod(function(foo){ //Here code using foo; });
Versprich Weg
Sie können Promise auch verwenden, um das zu lösen. Diese Methode unterstützt mehrere Aufrufe durch das Design des Versprechens:
var foo, callback; module.exports = new Promise(function(resolve, reject){ async.function(function(response) { foo = "foobar" resolve(foo); }); });
Hier
async.function
ist nur ein Platzhalter, um einen asynchronen Aufruf zu symbolisieren.In der Hauptsache
var fooMod = require('./foo.js').then(function(foo){ //Here code using foo; });
Siehe Promise-Dokumentation
quelle
if(typeof foo != 'undefined'){ cb(foo); // If foo is already define, I don't wait. } else { callback = cb; }
. (2) Bedeutet dieser Block, dassrequire
s dieses Modul so lange aufruft, bis es einen Wert ergibt (von seiner asynchronen Reise)? Oder wird davon ausgegangen, dass das Modul während seiner gesamten Lebensdauer nur einen Rückruf erhält, dh nachfolgende Aufrufe können dascb
Argument weglassen ?foo
Wert verwenden müssen, mehrere Male benötigt werden. Aber Sie wissen nicht, wann es passiert ist. Wenn es also früh ist und derfoo
Wert noch nicht vorhanden ist, speichern Sie die Rückrufe, um auf die Rückgabe des asynchronen Aufrufs zu warten. Am Ende des asynchronen Prozesses werden alle gespeicherten Rückrufe entstapelt und das Array wurde nicht mehr verwendet. Wenn zu diesem Zeitpunkt ein anderes Modul dieses Modul benötigt und abonniert, um denfoo
Wert abzurufen, ist der Wert bereits festgelegt, sodass Sie den Speicher umgehen, um den Rückruf direkt auszuführen.Ein ES7-Ansatz wäre eine sofort aufgerufene asynchrone Funktion in module.exports:
module.exports = (async function(){ //some async initiallizers //e.g. await the db module that has the same structure like this var db = await require("./db"); var foo = "bar"; //resolve the export promise return { foo }; })()
Dies kann mit späterem Warten erforderlich sein:
(async function(){ var foo = await require("./theuppercode"); console.log(foo); })();
quelle
ES6-Antwort mit Versprechungen:
const asyncFunc = () => { return new Promise((resolve, reject) => { // Where someAsyncFunction takes a callback, i.e. api call someAsyncFunction(data => { resolve(data) }) }) } export default asyncFunc ... import asyncFunc from './asyncFunc' asyncFunc().then(data => { console.log(data) })
Oder Sie können das Versprechen selbst direkt zurückgeben:
const p = new Promise(...) export default p ... import p from './asyncModule' p.then(...)
quelle
Promise
direkten zurückgeben? Wenn Sie dasPromise
direkt zurückgegeben haben, können Sie darauf zugreifenasyncFunc.then(...)
, oder? Ziemlich neu, also möchte ich deine Meinung einholen.const p = new Promise(...); export default p;
und dann in Ihrem Importmodulimport p from '...'; p.then(...);
id
oder andere Parameter). Im ersten Beispielconst asyncFunc = (id) => ...
könnten Sie dannid
in Ihrer Funktion verwenden. Du würdest es so nennenasyncFunc(id).then(...)
. Wenn Sie jedoch keine Argumente übergeben müssen, ist es auch in Ordnung, das Versprechen direkt zurückzugeben.Ein anderer Ansatz wäre das Umschließen der Variablen in ein Objekt.
var Wrapper = function(){ this.foo = "bar"; this.init(); }; Wrapper.prototype.init = function(){ var wrapper = this; async.function(function(response) { wrapper.foo = "foobar"; }); } module.exports = new Wrapper();
Wenn der Initialisierer einen Fehler aufweist, erhalten Sie zumindest immer noch den nicht initialisierten Wert, anstatt den Rückruf aufzuhängen.
quelle
Sie können auch Versprechen nutzen:
some-async-module.js
module.exports = new Promise((resolve, reject) => { setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000); });
main.js
var asyncModule = require('./some-async-module'); asyncModule.then(promisedResult => console.log(promisedResult)); // outputs 'someValueToBeReturned' after 2 seconds
Dasselbe kann in einem anderen Modul passieren und wird auch wie erwartet gelöst:
in-some-other-module.js
var asyncModule = require('./some-async-module'); asyncModule.then(promisedResult => console.log(promisedResult)); // also outputs 'someValueToBeReturned' after 2 seconds
Beachten Sie, dass das Versprechen-Objekt einmal erstellt und dann vom Knoten zwischengespeichert wird. Jeder
require('./some-async-module')
gibt dieselbe Objektinstanz zurück (in diesem Fall die Versprechen-Instanz).quelle
Andere Antworten schienen Teilantworten zu sein und funktionierten bei mir nicht. Dies scheint etwas vollständig zu sein:
some-module.js
var Wrapper = function(){ this.callbacks = []; this.foo = null; this.init(); }; Wrapper.prototype.init = function(){ var wrapper = this; async.function(function(response) { wrapper.foo = "foobar"; this.callbacks.forEach(function(callback){ callback(null, wrapper.foo); }); }); } Wrapper.prototype.get = function(cb) { if(typeof cb !== 'function') { return this.connection; // this could be null so probably just throw } if(this.foo) { return cb(null, this.foo); } this.callbacks.push(cb); } module.exports = new Wrapper();
main.js
var wrapper = require('./some-module'); wrapper.get(function(foo){ // foo will always be defined });
main2.js
var wrapper = require('./some-module'); wrapper.get(function(foo){ // foo will always be defined in another script });
quelle
callback(null, wrapper.foo);
stattcallback(wrapper.foo);
?