异步nodejs模块导出

Bre*_*ett 63 asynchronous node.js

我想知道配置模块导出的最佳方法是什么.以下示例中的"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;
Run Code Online (Sandbox Code Playgroud)

如何在执行异步回调后才导出模块?

编辑 我的实际用例的快速说明:我正在编写一个模块来在fs.exists()回调中配置nconf(https://github.com/flatiron/nconf)(即它将解析配置文件和设置nconf).

Tec*_*niv 52

您的导出无法正常工作,因为它在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里async.function只是一个象征异步调用的占位符.

主要的

var fooMod = require('./foo.js');
fooMod(function(foo){
    //Here code using foo;
});
Run Code Online (Sandbox Code Playgroud)

多种回调方式

如果需要多次调用模块,则需要管理一个回调数组:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里async.function只是一个象征异步调用的占位符.

主要的

var fooMod = require('./foo.js');
fooMod(function(foo){
    //Here code using foo;
});
Run Code Online (Sandbox Code Playgroud)

承诺的方式

您也可以使用Promise来解决这个问题.这种方法通过Promise的设计支持多次调用:

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

        resolve(foo);
    });
});
Run Code Online (Sandbox Code Playgroud)

这里async.function只是一个象征异步调用的占位符.

主要的

var fooMod = require('./foo.js').then(function(foo){
    //Here code using foo;
});
Run Code Online (Sandbox Code Playgroud)

请参阅Promise文档

  • 如果两个单独的(主)文件在没有foo准备好的情况下调用此函数,这将无效,对吧?只有一个回调会被解雇,无论哪个是最新的召唤它. (3认同)

ino*_*tia 11

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) })
Run Code Online (Sandbox Code Playgroud)

或者您可以直接返回Promise本身:

const p = new Promise(...)
export default p
...
import p from './asyncModule'
p.then(...)
Run Code Online (Sandbox Code Playgroud)


van*_*goz 10

另一种方法是将变量包装在对象中.

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();
Run Code Online (Sandbox Code Playgroud)

如果初始化程序有错误,至少你仍然得到未初始化的值而不是挂起回调.

  • 当您需要模块时,如何获得"foo"? (3认同)

Jon*_*lms 9

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
  };
})()
Run Code Online (Sandbox Code Playgroud)

稍后可能需要这样做:

(async function(){

  var foo = await require("./theuppercode");
  console.log(foo);
})();
Run Code Online (Sandbox Code Playgroud)


efi*_*les 8

你也可以使用Promises:

一些-异步module.js

module.exports = new Promise((resolve, reject) => {
    setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
Run Code Online (Sandbox Code Playgroud)

main.js

var asyncModule = require('./some-async-module');

asyncModule.then(promisedResult => console.log(promisedResult)); 
// outputs 'someValueToBeReturned' after 2 seconds
Run Code Online (Sandbox Code Playgroud)

在不同的模块中也会发生同样的情况,并且也会按预期解决:

在几家,其他-module.js

var asyncModule = require('./some-async-module');

asyncModule.then(promisedResult => console.log(promisedResult)); 
// also outputs 'someValueToBeReturned' after 2 seconds
Run Code Online (Sandbox Code Playgroud)

请注意,promise对象创建一次,然后由节点缓存.每个都require('./some-async-module')将返回相同的对象实例(在这种情况下为promise实例).