在运行时从文件动态加载函数
Dynamically load function from files at runtime
我有一些 nodejs 代码可以充当机器人玩游戏的仲裁者。
每个机器人都是它自己的文件,有一些预定义的 functions
和固定的名称(每个机器人都会用相同的名称和参数调用它的函数,比如 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();
}
}
});
你可以通过node的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();
}
}
});
});
正如@Kaito 所建议的,可以使用动态要求。但我绝不会喜欢那样,如果你不知道可能会出什么问题,那绝对不会。动态要求使您的应用程序容易出现您可能没有处理的运行时错误,例如需要一个不存在的文件(最常见的一个)。
我想在@Kaito 和@Yash 的基础上再接再厉suggested/provided。
解决方案
- 将您所有的机器人 files/functions 累积在一个地图中,该地图将
botname
映射到 botfilepath
- 按照您的逻辑,首先检查您是否有与正在加入的机器人相关的
botfile
/botfunction
- 如果是,那么您可以在运行时安全地要求
botfile
。
在下面的示例中,我假设所有机器人文件都将存储在 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] );
}
这种方法的好处 -
您在整个应用程序生命周期中生成一次文件操作并累积 botfile,从而减少昂贵的文件 ios 然后 if
部分安全地需要 botfile,具体取决于应用程序是否具有 bot 文件机器人加入。
缺点是-
您需要确保加入的机器人与 bots
目录中的 botfile
同名。
我有一些 nodejs 代码可以充当机器人玩游戏的仲裁者。
每个机器人都是它自己的文件,有一些预定义的 functions
和固定的名称(每个机器人都会用相同的名称和参数调用它的函数,比如 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();
}
}
});
你可以通过node的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();
}
}
});
});
正如@Kaito 所建议的,可以使用动态要求。但我绝不会喜欢那样,如果你不知道可能会出什么问题,那绝对不会。动态要求使您的应用程序容易出现您可能没有处理的运行时错误,例如需要一个不存在的文件(最常见的一个)。
我想在@Kaito 和@Yash 的基础上再接再厉suggested/provided。
解决方案
- 将您所有的机器人 files/functions 累积在一个地图中,该地图将
botname
映射到botfilepath
- 按照您的逻辑,首先检查您是否有与正在加入的机器人相关的
botfile
/botfunction
- 如果是,那么您可以在运行时安全地要求
botfile
。
在下面的示例中,我假设所有机器人文件都将存储在 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] );
}
这种方法的好处 -
您在整个应用程序生命周期中生成一次文件操作并累积 botfile,从而减少昂贵的文件 ios 然后 if
部分安全地需要 botfile,具体取决于应用程序是否具有 bot 文件机器人加入。
缺点是-
您需要确保加入的机器人与 bots
目录中的 botfile
同名。