asynchronousnodejs模块导出

我想知道什么是configuration模块导出的最佳方法。 在下面的例子中,“async.function”可能是一个FS或HTTP请求,为了举例而简化:

以下是示例代码(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; 

只有在执行了asynchronouscallback后,如何才能导出模块?

编辑一个关于我的实际用例的快速logging:我正在编写一个模块来在fs.exists()callback中configurationnconf( https://github.com/flatiron/nconf )(即它将parsing一个configuration文件,设置nconf)。

你的出口不能工作,因为它是在foo声明里面的时候在函数之外。 但是如果你把输出放在里面,当你使用你的模块时,你不能确定输出是被定义的。

使用ansync系统的最佳方式是使用callback。 您需要导出callback分配方法来获取callback,并在asynchronous执行时调用它。

例:

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

这里的async.function只是一个占位符来象征一个asynchronous调用。

主要

 var fooMod = require('./foo.js'); fooMod(function(foo){ //Here code using foo; }); 

多种callback方式

如果您的模块需要被多次调用,您需要pipe理一个callback数组:

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

这里的async.function只是一个占位符来象征一个asynchronous调用。

主要

 var fooMod = require('./foo.js'); fooMod(function(foo){ //Here code using foo; }); 

承诺的方式

你也可以用Promise来解决这个问题。 该方法通过Promise的devise支持多个呼叫:

 var foo, callback; module.exports = new Promise(function(resolve, reject){ async.function(function(response) { foo = "foobar" resolve(foo); }); }); 

这里的async.function只是一个占位符来象征一个asynchronous调用。

主要

 var fooMod = require('./foo.js').then(function(foo){ //Here code using foo; }); 

请参阅Promise文档

另一种方法是将variables包裹在一个对象中。

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

如果初始化器有错误,至less你仍然得到未初始化的值,而不是挂起callback。

你也可以使用Promises:

一些-asynchronousmodule.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 

在不同的模块中可能会发生同样的情况,并且也会像预期的那样解决

在几家,其他-module.js

 var asyncModule = require('./some-async-module'); asyncModule.then(promisedResult => console.log(promisedResult)); // also outputs 'someValueToBeReturned' after 2 seconds 

请注意,promise对象被创build一次,然后被节点caching。 每个require('./some-async-module')将返回相同的对象实例(在这种情况下是promise实例)。

ES6答案使用承诺:

 const asyncFunc = () => { return new Promise((resolve, reject) => { // Where someAsyncFunction takes a callback, ie api call someAsyncFunction(data => { resolve(data) }) }) } export default asyncFunc ... import asyncFunc from './asyncFunc' asyncFunc().then(data => { console.log(data) }) 

或者你可以直接返回承诺本身:

 const p = new Promise(...) export default p ... import p from './asyncModule' p.then(...) 

一个ES7的方法是在module.exports中立即调用asynchronous函数

 module.exports=(async function(){ //some async initiallizers //eg 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 }; })() 

稍后可能需要这样做:

 (async function(){ var foo= await require("./theuppercode"); console.log(foo); })(); 

其他答案似乎是部分答案,并没有为我工作。 这似乎有点完整:

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