Node.js 异步nodejs模块导出
我想知道配置模块导出的最佳方法是什么。下面示例中的“async.function”可以是FS或HTTP请求,为便于示例而简化: 下面是示例代码(asynmodule.js): 如何仅在执行异步回调后导出模块 编辑Node.js 异步nodejs模块导出,node.js,asynchronous,Node.js,Asynchronous,我想知道配置模块导出的最佳方法是什么。下面示例中的“async.function”可以是FS或HTTP请求,为便于示例而简化: 下面是示例代码(asynmodule.js): 如何仅在执行异步回调后导出模块 编辑 关于我的实际用例的简要说明:我正在编写一个模块,以便在fs.exists()回调中配置nconf()(即,它将解析一个配置文件并设置nconf) 导出无法工作,因为它在函数外部,而foo声明在内部。但是,如果将导出放在内部,则在使用模块时,无法确定是否定义了导出 使用ansync系统的
关于我的实际用例的简要说明:我正在编写一个模块,以便在fs.exists()回调中配置nconf()(即,它将解析一个配置文件并设置nconf) 导出无法工作,因为它在函数外部,而
foo
声明在内部。但是,如果将导出放在内部,则在使用模块时,无法确定是否定义了导出
使用ansync系统的最佳方法是使用回调。您需要导出回调分配方法来获取回调,并在异步执行时调用它
例如:
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
只是一个占位符,用来表示异步调用
大体上
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
var fooMod = require('./foo.js').then(function(foo){
//Here code using foo;
});
多重回调方式
如果需要多次调用模块,则需要管理回调数组:
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);
}
}
承诺方式
你也可以用承诺来解决这个问题。此方法通过Promise的设计支持多个调用:
var foo, callback;
module.exports = new Promise(function(resolve, reject){
async.function(function(response) {
foo = "foobar"
resolve(foo);
});
});
这里的async.function
只是一个占位符,用来表示异步调用
大体上
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
var fooMod = require('./foo.js').then(function(foo){
//Here code using foo;
});
请参见另一种方法是将变量包装在对象中
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();
如果初始值设定项有错误,至少您仍然会得到未初始化的值,而不是挂起回调。您还可以使用承诺: 一些异步模块.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
main.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
同样的情况也可能发生在不同的模块中,并将按预期解决: 在其他一些模块中。js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
请注意,promise对象创建一次,然后由节点缓存。每个
require('./some async module')
将返回相同的对象实例(本例中为promise实例)。其他答案似乎是部分答案,对我来说不起作用。这似乎有点完整:
一些模块.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
main.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
main2.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
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();
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
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) })
或者你可以直接回报承诺本身:
const p = new Promise(...)
export default p
...
import p from './asyncModule'
p.then(...)
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
};
})()
这在以后等待时可能需要:
(async function(){
var foo = await require("./theuppercode");
console.log(foo);
})();
我一直在玩弄我的实际用例,如果使用不存在的文件调用nconf.file(),那么nconf加载很好,所以现在我不需要解决方案。但是我仍然对这种方法感兴趣。我有同样的问题,我想导出一个承诺,并且
要求异步加载依赖项。我认为这是可能的巴贝尔格式化程序。然而,我认为这不是一个好的解决方案(如果两个独立的(主)系统不工作)文件在没有foo准备好的情况下调用此函数,对吗?只有一个回调会被触发,以最新调用的为准。在这种情况下,是的。因为我们不管理回调堆栈。但是使用一个数组来存储所有回调很容易解决这个问题。详细信息:ReferenceError:未定义异步我有两个问题:(1)在您的第一个示例中,else块的本质是什么?在这个示例中,您说if(typeof foo!=“undefined”){cb(foo);//如果foo已经定义,我就不等待了。}else{callback=cb;}
(2)这个块是否意味着需要s继续调用这个模块,直到它生成一个值(来自异步过程)?或者它是否假设在模块的整个生命周期内,只有一次回调给模块,即后续调用可以忽略cb
参数?@IWantAnswers,在这个例子中,不同的模块可能需要多次回调,需要使用foo
值。但您不知道何时发生。因此,何时开始回调,何时开始回调efoo
值不存在,但您存储回调以等待异步调用的返回。在异步过程结束时,所有存储的回调都取消堆栈,并且不再使用数组。此时,如果另一个模块需要此模块并订阅以获取foo
值,则该值已设置,因此您可以绕过当您需要模块时,如何获取“foo”?var wrapper=require('wrapper');console.log(wrapper.foo)这是ES6和Promission的正确、现代的答案。谢谢。问题:您直接返回函数而不是Promise
有什么原因吗?如果您直接返回Promise
,您可以使用asyncFunc访问它。然后(…)
,对吗?非常新,所以我想听听你的意见。那也行。我想当我写这个例子的时候,我是在导出一个异步方法的类,它的形式就像一个函数。但是你可以像这样导出承诺:const p=new Promise(…);导出默认p;
然后在您的导入模块中从“…”;p.then(…);
太棒了,感谢您的澄清。我想这是个人喜好,或者有最佳实践方法使用其中一种吗?我想这取决于您是否需要将参数传递给异步模块,这通常对我来说都是如此(例如,id
或其他参数)。在第一个示例中,如果const asyncFunc=(id)=>…
则可以在函数中使用id
。您可以像调用asyncFunc(id)一样调用它。然后(…)
。但是如果不需要传递任何参数,直接返回承诺也可以。为什么要使用回调(null,wrapper.foo);
而不是回调(wrapper.foo);
?@IWantAnswers第一个参数是error,第二个参数是result你能解释调用它和不调用它之间的区别/含义吗?如果你不调用函数,你在不执行的情况下导出函数