IPC: от страницы к главному процессу
IPC — обмен сообщениями между процессами. Самый частый случай: странице нужно, чтобы главный процесс что-то сделал и вернул результат, например прочитал заметки. Для этого главный процесс регистрирует обработчик через ipcMain.handle, а страница вызывает его через ipcRenderer.invoke и получает промис с ответом.
Обработчик в главном процессе
Сообщения различаются по имени канала — обычной строке. Принято писать её как тема:действие. Добавьте в main.js:
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
let notes = ['Купить хлеб', 'Позвонить Анне'];
app.whenReady().then(() => {
ipcMain.handle('notes:load', () => {
return notes;
});
createWindow();
});Функция-обработчик вызывается на каждый запрос по каналу notes:load. То, что она вернёт, получит страница. Пока заметки хранятся в памяти главного процесса.
Мост в preload
Страница не видит ipcRenderer, поэтому preload передаёт ей функцию-обёртку:
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('notes', {
load: () => ipcRenderer.invoke('notes:load'),
});invoke отправляет запрос и возвращает промис, который выполнится ответом обработчика.
Вызов со страницы
// renderer.js
const list = document.querySelector('#notes');
async function showNotes() {
const notes = await window.notes.load();
list.replaceChildren();
for (const note of notes) {
const li = document.createElement('li');
li.textContent = note;
list.append(li);
}
}
showNotes();После запуска в окне появятся две заметки из главного процесса.
Передача данных
Аргументы invoke приходят в обработчик после объекта события:
// main.js
ipcMain.handle('notes:add', (event, text) => {
notes.push(text);
return notes;
});// preload.js
contextBridge.exposeInMainWorld('notes', {
load: () => ipcRenderer.invoke('notes:load'),
add: (text) => ipcRenderer.invoke('notes:add', text),
});На странице форма вызывает await window.notes.add(text.value) и затем showNotes(). Данные передаются копией: строки, числа, массивы и простые объекты проходят, а функции и элементы DOM — нет.
Ошибки
Если обработчик выбросит ошибку, промис на странице будет отклонён:
// main.js
ipcMain.handle('notes:add', (event, text) => {
if (text.trim() === '') {
throw new Error('Пустая заметка');
}
notes.push(text);
return notes;
});На странице такой вызов оборачивают в try...catch и показывают сообщение пользователю.
Частая ошибка
Если вызвать ipcMain.handle внутри createWindow, то при повторном создании окна (например, по событию activate в macOS) Electron выбросит ошибку Attempted to register a second handler for 'notes:load'. Обработчик на канал можно зарегистрировать только один раз — делайте это один раз после whenReady, вне функции создания окна.