cpp

Выполнение операции в отдельном процессе

Если запустить на выполнение длительную операцию, то текущий процесс будет блокирован. В результате объект приложения или окно перестанут отвечать на действия пользователя и системы. Чтобы этого избежать, следует запустить длительную операцию в отдельном процессе. Запустить отдельный процесс позволяет функция fork() из модуля child_process. Формат функции:

const { fork } = require('child_process');
<ChildProcess> = fork(<Модуль>[, <Аргументы>][, <Опции>])

В первом параметре указывается путь к запускаемому в отдельном процессе модулю. Во втором параметре можно указать массив с передаваемыми аргументами. Третий параметр позволяет указать объект с опциями. Список опций см. в документации. Функция возвращает объект ChildProcess.

Модуль будет запущен в отдельном дочернем процессе, который изолирован от других процессов. Однако существует возможность обмена сообщениями между родительским и дочерним процессами. Чтобы отправить сообщение дочернему процессу, следует вызвать метод send() через объект ChildProcess:

let child = fork('test2.js');
child.send( {command: 'start', str: 'string'} );

Для отправки сообщения из дочернего процесса используется метод send() из модуля process:

process.send(s);

Передаваемые между процессами данные должны поддерживать сериализацию.

Чтобы получить сообщение в дочернем процессе, следует назначить обработчик события message с помощью метода on() из модуля process:

process.on('message', (obj) => {
   // ...
});

Внутри обработчика через параметр доступно значение, переданное методом send().

Чтобы получить сообщение, отправленное дочерним процессом, внутри родительского процесса, следует назначить обработчик события message с помощью метода on() через объект ChildProcess:

child.on('message', (s) => {
   // ...
});

Внутри обработчика через параметр доступно значение, переданное методом send().

Объект ChildProcess поддерживает следующие события:

  • message — из дочернего процесса отправлено сообщение с помощью метода send() из модуля process. Внутри обработчика через первый параметр доступны переданные данные;
  • error — генерируется при возникновении ошибки. Внутри обработчика через параметр доступен объект ошибки:
child.on('error', (e) => {
   console.log(e);
});
  • disconnect — вызван метод disconnect(). Обмен сообщениями становится невозможным:
child.on('disconnect', () => {
   console.log('disconnect');
});
  • close — при закрытии потоков дочернего процесса. Внутри обработчика через первый параметр доступен код завершения, если процесс завершился сам, или значение null. Через второй параметр доступен сигнал, по которому дочерний процесс был завершен, или значение null:
child.on('close', (code, signal) => {
   console.log('close', code, signal);
});
  • exit — после завершения работы дочернего процесса. Внутри обработчика через первый параметр доступен код завершения, если процесс завершился сам, или значение null. Через второй параметр доступен сигнал, по которому дочерний процесс был завершен, или значение null:
child.on('exit', (code, signal) => {
   console.log('exit', code, signal);
});

Принудительно завершить работу дочернего процесса из родительского процесса позволяет метод kill([<Сигнал>]). Если параметр не указан, то генерируется сигнал SIGTERM. Метод возвращает значение true, если операция выполнена успешно, и false — а противном случае:

child.kill();

Давайте рассмотрим пример. При нажатии кнопки получим содержимое текстового поля и выполним перевод букв в верхний регистр (просто для примера). Операцию запустим в отдельном процессе. Содержимое файла main.js приведено в листинге 11.2, файла index.html — в листинге 11.3, файла test.js — в листинге 11.4, а файла test2.js — в листинге 11.5.

Листинг 11.2. Содержимое файла C:\book\e1\main.js

const { app, BrowserWindow } = require('electron');

function createWindow() {
   const win = new BrowserWindow({
      width: 800,
      height: 600,
      webPreferences: {
         nodeIntegration: true,
         contextIsolation: false
      }
   });
   win.loadFile('index.html');
   win.webContents.openDevTools();
}

app.whenReady().then( () => {
   createWindow();
   app.on('activate', () => {
      if (BrowserWindow.getAllWindows().length === 0) {
         createWindow();
      }
   });
} );

app.on('window-all-closed', () => {
   if (process.platform !== 'darwin') {
      app.quit();
   }
});

Листинг 11.3. Содержимое файла C:\book\e1\index.html

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta http-equiv="Content-Security-Policy"
         content="default-src 'self'">
   <title>Выполнение операции в отдельном процессе</title>
</head>
<body>
   <h1>Выполнение операции в отдельном процессе</h1>
   <input type="text" id="txt1">
   <button type="button" id="btn1">Запустить процесс</button><br>
   <div id="result"></div>
   
   <script src="test.js"></script>
</body>
</html>

Листинг 11.4. Содержимое файла C:\book\e1\test.js

const { fork } = require('child_process');

document.getElementById('btn1').addEventListener('click', () => {
   let txt1 = document.getElementById('txt1');
   let result = document.getElementById('result');
   if (txt1.value === '') {
      result.innerHTML = 'Не заполнено поле';
      return;
   }
   let child = fork('test2.js');
   child.on('message', (s) => {
      result.innerHTML = s;
      child.send( {command: 'exit'} );
      // child.kill();
   });
   child.on('exit', (code, signal) => {
      console.log('exit', code, signal);
   });
   child.on('error', (e) => {
      console.log(e);
   });
   child.on('close', (code, signal) => {
      console.log('close', code, signal);
   });
   child.on('disconnect', () => {
      console.log('disconnect');
   });
   child.send( {command: 'start', str: txt1.value} );
});

Листинг 11.5. Содержимое файла C:\book\e1\test2.js

function start(str) {
   return str.toUpperCase();
}

process.on('message', (obj) => {
   if (obj.command === 'start') {
      let s = start(obj.str);
      process.send(s);
   }
   else if (obj.command === 'exit') {
      process.exit();
   }
});

Учебник по Electron js
Учебник по Electron js в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp