在运行时从文件动态加载功能

时间:2018-08-28 12:46:09

标签: javascript node.js require

我有一些nodejs代码,可以充当机器人玩游戏的仲裁器。

每个bot都是它自己的文件,带有一些具有固定名称的预定义functions(每个bot都将其函数使用相同的名称和参数,例如PlayRound())。

现在,我想在runtime处添加游戏中的机器人。就像我告诉仲裁者botName1一样,它将在bots文件夹中查找一个名为botName1.js的文件,然后可以稍后调用botName1.PlayRound()

由于require似乎仅适用于文字静态字符串,并且不适用于运行时值,所以甚至有办法做到这一点?

示例代码:

const readline = require('readline');
const readLine = readline.createInterface({ input: process.stdin });

var players = []
var playerFiles = [];

readLine.on('line', (ln) => {

    var ws = ln.split(' ');

    if (ws[0].toLowerCase() === 'add') {
        players[players.length] = ws[1];
        // I would like to add the file corresponding to the name here
    } else if (ws[0].toLowerCase() === 'list'){
        console.log('There are currently ' + players.length + ' players registered:');
        for (var p in players) {
            console.log(players[p]);
        }
    } else if (ws[0].toLowerCase() === 'start'){
        // I would like to do this here
        for (var playerFile in playerFiles) {
            playerFiles[playerFile].PlayRound();
        }
    }

});

2 个答案:

答案 0 :(得分:1)

您可以通过节点的fs包获取此信息

 fs.readdirSync(PATHOFDIRECTORYCONTAININGFILEs)
       .forEach((file) =>  {
        var name = file.replace('.js', '');
        if(name === botname) {
          require('./' + file).PlayRound();
        }
    });

尝试

 const readline = require('readline');
 const fs = require('fs);
 const readLine = readline.createInterface({ input: process.stdin });

 var players = []
 var playerFiles = [];

 readLine.on('line', (ln) => {

var ws = ln.split(' ');

if (ws[0].toLowerCase() === 'add') {
    players[players.length] = ws[1];
    //
} else if (ws[0].toLowerCase() === 'list'){
    console.log('There are currently ' + players.length + ' players 
        registered:');
    for (var p in players) {
        console.log(players[p]);
    }
} else if (ws[0].toLowerCase() === 'start'){
    // I would like to do this here

   fs.readdirSync(__diname)
   .forEach((file) =>  {
       for (var playerFile in playerFiles) {
         var name = file.replace('.js', '');
         if(name === playerFile) {
         require('./' + file).PlayRound();
        }
     }
  });
});

答案 1 :(得分:1)

正如@Kaito所建议的,可以使用动态需求。但是我绝对不会喜欢,如果您不知道可能出什么问题,绝对不会。动态要求使您的应用程序容易遇到未解决的运行时错误,例如需要不存在的文件(最常见的一个)。

我想以@Kaito和@Yash所建议/提供的内容为基础。

解决方案

  1. 在将botname映射到botfilepath的映射中累积所有bot文件/功能
  2. 按照您的逻辑,首先检查您是否有与要加入的机器人相关的botfile / botfunction
  3. 如果是,那么您可以放心地在运行时要求botfile

在下面的示例中,我假设所有bot文件都将存储在bots目录中。

示例

const fs        = require( "fs" ),
      path      = require( "path" ),
      botsDir   = path.join( __dirname, "bots" );

/** One time read to fetch all the bot files in bots dir */
const files         = fs.readdirSync( botsDir ),
      /** Here we create the map of bot and bot file path */
      availableBots = files
                        .reduce( ( botMap, file ) => Object.assign( botMap, { 
                            [ file.replace(".js", "") ] : path.join( botsDir, file ) 
                        } ), {} );

// Your code
const botThatWillBeJoiningAtRuntime = "BotC"; // This would be some calculation to determine bot that joins at runtime.

/** Here we safely require the bot file only if we have one corresponding to the bot that is joining */
if ( availableBots[botThatWillBeJoiningAtRuntime] ) {
    const botFunc = require( availableBots[botThatWillBeJoiningAtRuntime] );
}

此方法的优点-

您在整个应用程序生命周期中一次使文件op并累积botfile,从而减少了昂贵的文件ios,然后if部分会根据应用程序是否具有要加入的bot bot文件来安全地需要botfile。 / p>

缺点是-

您需要确保加入的漫游器与botfile目录中的bots具有相同的名称。