Node.js и область модуля: самый эффективный способ чтения файлов в память

Я пытаюсь лучше понять область действия модуля node.js и требования в контексте создания экземпляра переменной. Точнее, чтение файлов в память.

У меня есть http-сервер с модулем, который читает статические файлы sql, хранящиеся в кодовой базе, и выполняет содержащиеся в них запросы. Например:

'use strict';

const fs = require('fs')
const executeSql = require('./utils/execute-sql');

module.exports.getDataById = (id) => {
  const sql = fs.readFileSync(
    `./data-access/sql/getDataById.sql`, 'utf8'
  );

  return executeSql(sql, id);
}

module.exports.getDataByName = (name) => {
  const sql = fs.readFileSync(
    `./data-access/sql/getDataByName.sql`, 'utf8'
  );

  return executeSql(sql, name);
}

Насколько я понимаю, каждый раз, когда вызываются эти функции (getDataById и getDataByName), файл читается синхронно блокирующим образом и блокирует поток выполнения. Я знаю, что могу читать файлы асинхронно, чтобы избежать этого, но мне действительно любопытно, означает ли вытягивание переменных sql из функции и в область модуля операции readFile только один раз (когда создается экземпляр процесса узла) и в конечном итоге будет более эффективным. Например:

'use strict';

const fs = require('fs')
const executeSql = require('./utils/execute-sql');
const sql1 = fs.readFileSync(
  `./data-access/sql/getDataById.sql`, 'utf8'
);
const sql2 = fs.readFileSync(
  `./data-access/sql/getDataByName.sql`, 'utf8'
);

module.exports.getDataById = (id) => {
  return executeSql(sql1, id);
}

module.exports.getDataByName = (name) => {
  return executeSql(sql2, name);
}

Я знаю, что require загружает модули синхронно при инициализации процесса node и дополнительно кэширует эти модули, если они потребуются где-то еще, но я пытаюсь понять, если стандартные объявления переменных, НЕ использующие require, приводят к аналогичному экземпляру ссылки на память, которая сохраняется в течение всего времени существования процесса узла, и его не нужно повторно создавать каждый раз, когда требуется модуль.

Я ценю любую информацию, которую вы можете предоставить.


person willascend    schedule 02.08.2018    source источник
comment
Я видел, что у вас был другой вопрос с действительным ответом, но он не был принят. Старайтесь поддерживать высокое соотношение сделанных вопросов и принятых ответов, чтобы люди больше помогали вам, если вы положительно оценивали время, которое они тратят на помощь вам.   -  person Jorge Fuentes González    schedule 02.08.2018
comment
Спасибо за отзыв об этом @JorgeFuentesGonzález! Я не согласился, потому что искал дополнительные ответы, не связанные с перенаправлением. Это правильный ответ с точки зрения вариантов, но на самом деле он не дал ответа, который я искал, с этим дополнительным ограничением. Я соглашусь, тем более, что с момента написания прошло много времени.   -  person willascend    schedule 02.08.2018
comment
О, здорово тогда :-)   -  person Jorge Fuentes González    schedule 02.08.2018


Ответы (1)


Ты прав. Каждый раз, когда модулю требуется другой модуль, код выполняется только в первый раз, а в остальных случаях он просто возвращает кэшированный exports, поэтому в вашем примере fs.readFileSync будет запущен один раз (в первый раз, когда он кому-то понадобится), node .js будет кэшировать объект exports и в следующем требует, чтобы объект exports был возвращен без повторного запуска кода.

Вы можете проверить это примерно так:

var mod = require("./myModule");
console.log(mod.nonExistantProperty); // This will log undefined
mod.nonExistantProperty = "yay";

var requireagain = require("./myModule");
console.log(requireagain.nonExistantProperty); // This will log yay

Во втором запросе вместо повторного выполнения кода модуля он просто вернет объект, который был закэширован, поэтому вы можете увидеть изменения, которые вы сделали, прежде чем запрашивать его во второй раз.

С этой информацией в вашем первом примере вы возвращаете функции в экспорте, которые будут выполнять свой код каждый раз, когда вы их вызываете (очевидно), поэтому, если у вас есть метод readfile внутри функции, он будет запускаться каждый раз.

Ваш второй подход обычно используется для повышения производительности, поскольку код запускается только один раз (при первом запросе), и каждый раз, когда выполняются экспортированные функции, они будут получать доступ к содержимому переменной, в котором уже кэшировано содержимое файла. Престижность за то, что вы пришли к такому выводу :-) так держать.

person Jorge Fuentes González    schedule 02.08.2018
comment
Спасибо, @jorge-fuentes-gonzalez! Я хотел бы получить одно уточнение. Итак, простое создание экземпляра ссылки на переменную в области модуля фактически кэширует ее в контексте модели, или я должен использовать require для получения этого кэширования? Итак, разница между const sql1 = fs.readFileSync('./data-access/sql/getDataById.sql', 'utf8'); и const sql1 = require(fs.readFileSync('./data-access/sql/getDataById.sql', 'utf8')) --- не уверен, что последний код действительно работает, но я думаю, вы поняли мою точку зрения. - person willascend; 02.08.2018
comment
@willascend Нет, последнее не сработает. Контекст искажается, как вы сказали, да. - person Jorge Fuentes González; 02.08.2018