Можно выгрузить, удалить или отменить запрос Nodejs модуля - PullRequest
2 голосов
/ 26 января 2020

Мы создаем приложение Electron, которое позволяет пользователям предоставлять собственные «модули» для запуска. Мы ищем способ требовать модули, но затем удаляем или убиваем модули, если это необходимо. Мы просмотрели несколько учебных пособий, в которых обсуждается эта топи c, но мы не можем заставить модули полностью завершиться. Мы исследовали это с помощью таймеров внутри модулей и можем наблюдать, как таймеры продолжают работать даже после удаления ссылки на модуль.

https://repl.it/repls/QuerulousSorrowfulQuery

index.js

// Load module
let Mod = require('./mod.js'); 

// Call the module function (which starts a setInterval)
Mod();

// Delete the module after 3 seconds
setTimeout(function () {
  Mod = null;
  delete Mod;
  console.log('Deleted!')
}, 3000);

./mod.js

function Mod() {
  setInterval(function () {
    console.log('Mod log');
  }, 1000);
}

module.exports = Mod;

Ожидаемый результат

Mod log
Mod log
Deleted!

Фактический результат

Mod log
Mod log
Deleted!
Mod log 
...
(continues to log 'Mod log' indefinitely)

Может быть, мы переосмысливаем это, и, возможно, модули не будут загружать память, но загружаемые нами модули будут иметь очень интенсивные рабочие нагрузки, и возможность остановить их по своему усмотрению кажется важной. Редактировать с реальным вариантом использования

Вот как мы в настоящее время используем эту технику. Две проблемы - загрузка модуля надлежащим образом и выгрузка модуля после его завершения.

renderer.js (выполняется в контексте браузера с доступом к document, et c)

const webview = document.getElementById('webview'); // A webview object essentially gives us control over a webpage similar to how one can control an iframe in a regular browser.
const url = 'https://ourserver.com/module.js';
let mod;
request({
  method: 'get',
  url: url,
}, function (err, httpResponse, body) {
  if (!err) {
    mod = requireFromString(body, url); // Module is loaded
    mod(webview); // Module is run
    // ...
    // Some time later, the module needs to be 'unloaded'. 
    // We are currently 'unloading' it by dereferencing the 'mod' variable, but as mentioned above, this doesn't really work. So we would like to have a way to wipe the module and timers and etc and free up any memory or resources it was using!
    mod = null;
    delete mod;
  } 
})

function requireFromString(src, filename) {
  var Module = module.constructor;
  var m = new Module();
  m._compile(src, filename);
  return m.exports;
}

https://ourserver.com/module.js

// This code module will only have access to node modules that are packaged with our app but that is OK for now!
let _ = require('lodash'); 
let obj = {
  key: 'value'
}
async function main(webview) {
  console.log(_.get(obj, 'key')) // prints 'value'
  webview.loadURL('https://google.com') // loads Google in the web browser
}

module.exports = main;

На всякий случай, если любой читающий не знаком с Electron, renderer.js имеет доступ к элементам 'webview', которые почти идентичны элементам iframe. Вот почему его передача в модуль. js позволит модулю получить доступ к манипулированию веб-страницей, такой как изменение URL-адреса, нажатие кнопок на этой веб-странице и т. Д. c.

1 Ответ

2 голосов
/ 26 января 2020

Нет способа убить модуль и остановить или закрыть любые ресурсы, которые он использует. Это просто не особенность node.js. Такой модуль может иметь таймеры, открытые файлы, открытые сокеты, запущенные серверы и т. Д. c ... Кроме того, node.js не предоставляет средства для «выгрузки» кода, который когда-то был загружен.

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

Единственный известный мне надежный способ - это загрузить пользовательский модуль в отдельном node.js приложении, загруженном как дочерний процесс, и затем вы можете выйти из этого процесса или завершить его, а затем ОС вернет все использованные ресурсы и выгрузит все из памяти. Эта схема дочерних процессов также имеет то преимущество, что код пользователя более изолирован от кода вашего основного сервера. Вы можете даже изолировать его, запустив этот другой процесс на ВМ, если хотите.

...