2016-07-25 82 views
0

我试图通过要求与匿名函数的文件和传递的参数来调用带有一个参数module.exports导出的自执行匿名函数从另一个文件的NodeJS Object对象是这样的:如何将参数传递给自执行的module.exported匿名节点函数?

fileThatCallsTheAnonymousSelfExecutingFunction: `

var parameters = { 
    filename: "UsernamesAndQueues", 
    headers: ["username", "password", "queue"], 
    columns: ["ascii", "ascii", "ascii"], 
    wordLength: 25, 
    count: 100 
}; 

var generateData = require("../scripts/generateData.js")(parameters); 

generateData.js:

// if the function does not call itself in this file, i can pass the 
// arguments normally, and it prints out the expected options. 

module.exports = (function (options) { 

    console.log("Hello %s", JSON.stringify(options)); 
    options = options || { 
          "headers": ["username", "password", "queueName"], 
          "columns": ["ascii", "ascii", "ascii"], 
          "wordLength": 26, 
          "count": 101 
         }; 

    console.log("Current options are: %s", JSON.stringify(options)); 
    // I just want to know what the arguments are for now, so I interrupt 
    process.exit(); 
    // i just want for the moment to print out the options object 
    // later on, i would like to use the options as i would parse arguments ??? options[0], options[1], options[2] etc. 

    // rest of the file that really needs the function arguments 
    console.log("something"); 
    var fs = require('fs'), 
     generate = require('csv-generate'), 
     filename = "UsernamesAndQueues", 
     csvfilestream = fs.createWriteStream("../data/" + "generated" + filename + ".csv", { flags: 'w' }), 
     error = fs.createWriteStream(__dirname + '/node.error.log', {flags: 'w'}), 
     // CSV generator (read command line arguments, create with defaults, making filename required) 
     generator = generate({ 
      header: options.headers, 
      columns: options.columns, 
      max_word_length: options.wordLength, 
      length: options.count 
     }); 

     // Redirect stdout/stderr to file 
     process.stdout.write = csvfilestream.write.bind(csvfilestream); 
     process.stderr.write = error.write.bind(error); 

     // Handle Uncaught Exceptions/Errors 
     process.on('uncaughtException', function(err){ 
      console.error((err && err.stack) ? err.stack : err); 
     }); 

     // Output CSV to stdout stream -> to file 
     generator.pipe(process.stdout); 
})(arguments[0]); 

我在问什么是处理传递给函数的参数的正确方法?我想这样做,以便从cmd行调用它,以及(可选)命令行参数。在弄清楚如何以这种方式进行操作之后,我可以进一步使用参数解析器。

如果有实现节点脚本(功能),其可以作为一个命令行脚本(node generateData.js --headers ["param1", "param2", "param3"] --columns ["ascii", "ascii", "ascii"] --wordLength 25 --count 100并作为所需的模块导出函数文件到另一个运行,并通过像上述的参数对象(var generateData = require("../scripts/generateData.js")(parameters);)的其他建议,请做一个机智的回应!

其他问题:我在做什么正确的,我做错了什么,什么和在哪里可以阅读,以更好地理解这些概念?我看了Mozilla Dev和其他一些网站。我发现有关自动执行匿名函数的参数,但没有一个从外部文件调用。也许我甚至没有寻找正确的东西...

后来编辑: 我已经尝试导出函数并从另一个文件调用它。这是简单的方法。

scriptThatRequiresTheExportedModuleAndCallsItWithParameters(参数).js文件

var parameters = { 
    headers: ["username", "password", "queue"], 
    columns: ["ascii", "ascii", "ascii"], 
    word_length: 25, 
    count: 100 
}; 
// this works 
var generateUsernames = require('../scripts/generateData.js')(parameters); 

generateData.js

// this works, just exporting the function, without self-executing (calling) 
// i call the function (providing arguments) from the other file requiring it 
module.exports = function (options) { 
    console.log("Hello %s", JSON.stringify(options)); 
    options = options || { 
          "headers": ["username", "password", "queueName"], 
          "columns": ["ascii", "ascii", "ascii"], 
          "wordLength": 26, 
          "count": 101 
         }; 
    console.log("Current options are: %s", JSON.stringify(options)); 
    // exiting, because, for now, i just want to know what the arguments (options) are 
    process.exit(); 
    console.log("something"); 
    var fs = require('fs'), 
     generate = require('csv-generate'), 
     filename = "UsernamesAndQueues", 
     csvfilestream = fs.createWriteStream("../data/" + "generated" + filename + ".csv", { flags: 'w' }), 
     error = fs.createWriteStream(__dirname + '/node.error.log', {flags: 'w'}), 

    // CSV generator (read command line arguments, create with defaults, making filename required) 
    generator = generate({ 
     header: options.headers, 
     columns: options.columns, 
     max_word_length: options.wordLength, 
     length: options.count 
    }); 

    // Redirect stdout/stderr to file 
    process.stdout.write = csvfilestream.write.bind(csvfilestream); 
    process.stderr.write = error.write.bind(error); 

    // Handle Uncaught Exceptions/Errors 
    process.on('uncaughtException', function(err){ 
     console.error((err && err.stack) ? err.stack : err); 
    }); 

    // Output CSV to stdout stream -> to file 
    generator.pipe(process.stdout); 
}; 
+1

而挑剔:它不是*自我执行*,它只是内联调用。它的口语是IIFE(内联调用的函数表达式)。 –

+2

@ T.J.Crowder我认为这意味着*立即* - 调用函数表达式。 – 2016-07-25 19:01:08

+0

@torazaburo:我听说过这两种,但是你的是我喜欢和想要使用的。 :-) –

回答

1

正如jfriend00指出的那样:“...... [你的代码]立即执行,而不是以后有人使用你的模块决定调用它。”您需要将的功能分配给require以按预期方式使用它。

要获得您要查找的“具有节点generateData.js [参数列表]的命令行”行为,可以添加一个条件,检查上下文是否为CLI,然后调用该函数,或者导出if不是:

var fancyFn = function(options) { 
    ... 
}; 
if (require.main === module) { 
    fancyFn(arguments[0]); 
} else { 
    module.exports = fancyFn; 
} 
+0

[来自文档](https://nodejs.org/api/modules.html#modules_accessing_the_main_module):*当一个文件直接从Node.js运行时,require.main被设置为它的模块*但是,我建议你考虑@ jfriend00的答案。在模块文件中保存这种逻辑将导致在所有模块文件中保留这种逻辑。是的,你*可以*做到这一点。虽然你可能*不应该*。 – Will

+0

是的,这可能是一种可能性,我想。虽然,这类似于_pythonic_做事的方式。 require.main属性是什么?我可以在哪里读到关于这个的内容,以免额外的解释让你更烦恼? 我会尝试上面的方式和示例,并回来感谢你(我已经知道这将工作,我会回来标记答案: - “) 在第一个分支有条件的,我甚至可以解析cmd行参数并显示一个帮助菜单,然后构建_options_对象并调用fancyFn –

+0

您能想到长期使用这种方法的后果吗?(每个模块一个文件,为每一个参数进行参数解析;而不是在每个模块中使用一个文件,在另一个文件中使用命令行util) –

3

您没有适当的结构。自动执行(技术上“内联调用”)立即执行,而不是稍后使用模块的人决定调用它时。看起来你只是想导出一个普通的函数,根本不需要自动执行部分。然后,模块的调用者将根据您的使用模式显示提供参数。

就改成这样:

module.exports = function (options) { 

    console.log("Hello %s", JSON.stringify(options)); 
    options = options || { 
          "headers": ["username", "password", "queueName"], 
          "columns": ["ascii", "ascii", "ascii"], 
          "wordLength": 26, 
          "count": 101 
         }; 

    console.log("Current options are: %s", JSON.stringify(options)); 
    process.exit(); 
    // i just want for the moment to print out the options object 
    // later on, i would like to use the options as i would parse arguments ??? options[0], options[1], options[2] etc. 

    // rest of the file that really needs the function arguments 
    console.log("something"); 
    var fs = require('fs'), 
     generate = require('csv-generate'), 
     filename = "UsernamesAndQueues", 
     csvfilestream = fs.createWriteStream("../data/" + "generated" + filename + ".csv", { flags: 'w' }), 
     error = fs.createWriteStream(__dirname + '/node.error.log', {flags: 'w'}), 
     // CSV generator (read command line arguments, create with defaults, making filename required) 
     generator = generate({ 
      header: options.headers, 
      columns: options.columns, 
      max_word_length: options.wordLength, 
      length: options.count 
     }); 

     // Redirect stdout/stderr to file 
     process.stdout.write = csvfilestream.write.bind(csvfilestream); 
     process.stderr.write = error.write.bind(error); 

     // Handle Uncaught Exceptions/Errors 
     process.on('uncaughtException', function(err){ 
      console.error((err && err.stack) ? err.stack : err); 
     }); 

     // Output CSV to stdout stream -> to file 
     generator.pipe(process.stdout); 
}; 

附:为什么你的函数中间有一个process.exit();,这会导致其余部分未被使用?


如果你希望能够使用这个命令行或作为常规模块别人通话,那么你就可以做出获取命令行参数的另一个小模块,加载该模块并调用它。这是我不清楚你到底怎么想的命令行参数的工作,但总的结构应该是这样:

// command line module processing module 
// gendata.js 

// load the generateData module 
var gData = require('./generateData.js'); 

var options = {}; 
// some code here to process the command line arguments in process.argv 
// into the options object 

// call the other module with the command line arguments in the options object 
gData(options); 

然后,你可以在命令行中执行此:

node gendata.js arg1 arg2 arg3 
+0

我希望函数在节点generateData.js [参数列表]的命令行中执行,并且需要另一个节点脚本中的文件(模块)var generateData = require('generateData.js')(arguments)。我已经在generateData.js的第一条评论中说过,我知道并尝试了你指出的版本。我正在寻找一种调用函数的双重使用方式。 你会如何执行这个函数作为命令行中的脚本?无需进入节点环境本身:作为节点generateData.js [选项]? –

+0

@brainsearching - 命令行参数在'process.argv'中。一个给定的模块必须知道它是被要求处理命令行参数还是只是一个模块供其他人来调用。我建议你制作一个小的模块,执行命令行的东西并加载这个模块。我会给我的答案添加一个例子。 – jfriend00

+0

将CLI魔法的责任从模块魔法中分离出来的好消息。 – Will

相关问题