异步 nodejs 模块导出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20238829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Asynchronous nodejs module exports
提问by Brett
I was wondering what the best approach is for configuring a module export. "async.function" in the example below could be a FS or HTTP request, simplified for the sake of the example:
我想知道配置模块导出的最佳方法是什么。下面示例中的“async.function”可以是 FS 或 HTTP 请求,为了示例而简化:
Here's example code (asynmodule.js):
这是示例代码(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;
How can I export the module only once the async callback has been executed?
如何仅在执行异步回调后才导出模块?
edita quick note on my actual use-case: I'm writing a module to configure nconf (https://github.com/flatiron/nconf) in an fs.exists() callback (i.e. it will parse a config file and set up nconf).
编辑关于我的实际用例的快速说明:我正在编写一个模块来在 fs.exists() 回调中配置 nconf ( https://github.com/flatiron/nconf)(即它将解析配置文件并设置 nconf)。
采纳答案by Techniv
Your export can't work because it is outside the function while the foodeclaration is inside. But if you put the export inside, when you use your module you can't be sure the export was defined.
您的导出无法工作,因为它在函数外部而foo声明在内部。但是如果你把导出放在里面,当你使用你的模块时,你不能确定导出是否被定义。
The best way to work with an ansync system is to use callback. You need to export a callback assignation method to get the callback, and call it on the async execution.
使用异步系统的最佳方式是使用回调。您需要导出一个回调分配方法来获取回调,并在异步执行时调用它。
Example:
例子:
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;
}
}
Here async.functionis just a placeholder to symbolise an async call.
这里async.function只是一个象征异步调用的占位符。
In main
在主要
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Multiple callback way
多种回调方式
If your module need to be called more than once you need to manage an array of 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);
}
}
Here async.functionis just a placeholder to symbolise an async call.
这里async.function只是一个象征异步调用的占位符。
In main
在主要
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Promise way
承诺方式
You can also use Promise to solve that. This method support multiple call by the design of the Promise:
你也可以使用 Promise 来解决这个问题。该方法通过 Promise 的设计支持多次调用:
var foo, callback;
module.exports = new Promise(function(resolve, reject){
async.function(function(response) {
foo = "foobar"
resolve(foo);
});
});
Here async.functionis just a placeholder to symbolise an async call.
这里async.function只是一个象征异步调用的占位符。
In main
在主要
var fooMod = require('./foo.js').then(function(foo){
//Here code using foo;
});
回答by inostia
ES6 answer using promises:
ES6 使用承诺回答:
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) })
Or you could return the Promise itself directly:
或者你可以直接返回 Promise 本身:
const p = new Promise(...)
export default p
...
import p from './asyncModule'
p.then(...)
回答by Jonas Wilms
An ES7 approach would be an immediatly invoked async functionin module.exports :
ES7 方法是在 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
};
})()
This can be required with await later:
这可能需要稍后等待:
(async function(){
var foo = await require("./theuppercode");
console.log(foo);
})();
回答by vangoz
Another approach would be wrapping the variable inside an object.
另一种方法是将变量包装在一个对象中。
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();
If the initializer has error, at least you still get the uninitialized value instead of hanging callback.
如果初始化器有错误,至少你仍然得到未初始化的值而不是挂起回调。
回答by efidiles
You can also make use of Promises:
您还可以使用 Promises:
some-async-module.js
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
The same can happen in a different module and will also resolve as expected:
同样的情况也可能发生在不同的模块中,并且也会按预期解决:
in-some-other-module.js
in-some-other-module.js
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
Note that the promise object is created once then it's cached by node. Each require('./some-async-module')will return the same object instance (promise instance in this case).
请注意,promise 对象创建一次,然后由节点缓存。每个都require('./some-async-module')将返回相同的对象实例(在本例中为 promise 实例)。
回答by tsuz
Other answers seemed to be partial answers and didn't work for me. This seems to be somewhat complete:
其他答案似乎是部分答案,对我不起作用。这似乎有些完整:
some-module.js
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
main2.js
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});

