Привязки
deno desktop доступно начиная с Deno v2.9.0. Если у вас более ранняя версия, обновите Deno, чтобы использовать эту возможность.
win.bind(name, handler) предоставляет функцию на стороне Deno веб-представлению. Из веб-представления вызовите её как bindings.<name>(args), и вызов вернёт Promise, которое разрешится значением, возвращённым обработчиком.
win.bind("readSettings", async () => {
const text = await Deno.readTextFile("settings.json");
return JSON.parse(text);
});
win.bind("saveSettings", async (settings) => {
await Deno.writeTextFile("settings.json", JSON.stringify(settings, null, 2));
});
const settings = await bindings.readSettings();
settings.theme = "dark";
await bindings.saveSettings(settings);
Как это работает
Привязки — это не IPC. Среда выполнения Deno и сервер отрисовки работают как потоки / процессы в одном адресном пространстве (CEF) или в согласованной группе процессов (WebView). Вызовы передаются по внутрипроцессным каналам, а сервер отправляет их на выполнение из своего цикла обработки событий.
Это позволяет избежать межпроцессного обмена данными туда и обратно, который требуют основанные на сокетах фреймворки IPC (ipcMain / ipcRenderer Electron, invoke Tauri). Аргументы и результаты по-прежнему кодируются при пересечении границы между областями видимости, но передача данных происходит внутри процесса: без сокетов и планирования между процессами.
На практике привязки работают достаточно быстро, поэтому для типичных задач приложения вам не нужно беспокоиться о частоте вызовов.
Прокси веб-представления
bindings на стороне веб-представления — это Proxy. При каждом обращении к свойству функция создаётся по запросу:
bindings.foo; // function
bindings.foo("a", 1); // Promise<unknown>
Прокси не проверяет имена: если вместо bindings.readSettings указать bindings.readSetings, ошибки при обращении к свойству не возникнет; она появится при вызове (вызов будет отклонён, поскольку такая привязка не зарегистрирована).
Семантика аргументов и возвращаемых значений
Аргументы и возвращаемые значения кодируются в JSON при передаче между веб-представлением и средой выполнения Deno. Это означает следующее:
- Обычные объекты, массивы, строки, числа, логические значения и
nullпередаются без изменений. -
Uint8Arrayподдерживается для передачи двоичных данных. -
undefinedи необязательные свойства удаляются при сериализации. -
Date,Map,Set,RegExp, типизированные массивы, кромеUint8Array, иArrayBuffer: не сохраняются. Прежде чем отправлять их, преобразуйте их в структуру, совместимую с JSON (Dateстановится строкой, аMapстановится{}). - Функции, узлы DOM, прототипы и циклические ссылки нельзя передавать.
- Ошибки, выброшенные обработчиком, передаются веб-представлению как
{ name, message, stack }(см. раздел Ошибки ниже), а не как экземплярError.
Используйте простые данные и Uint8Array с обеих сторон.
Асинхронные обработчики
Обработчики могут быть синхронными или асинхронными. Веб-представление всегда получает Promise:
win.bind("now", () => Date.now()); // sync
win.bind("delay", async (ms) => { // async
await new Promise((r) => setTimeout(r, ms));
});
const t = await bindings.now();
await bindings.delay(500);
Ошибки
Если обработчик выбрасывает исключение — синхронно или через отклонённый промис, — вызов со стороны веб-представления будет отклонён:
win.bind("readFile", async (path) => {
return await Deno.readTextFile(path);
});
try {
await bindings.readFile("/missing");
} catch (e) {
console.error(e); // NotFound: …
}
Веб-представление получает ошибку как обычный объект { name, message, stack }. Чтобы определить тип ошибки, проверьте error.name.
Удаление привязки
win.unbind("readSettings");
Удаляет привязку. Последующие вызовы bindings.readSettings() будут отклонены.
Разрешения
Привязки выполняются в среде выполнения Deno, поэтому наследуют разрешения процесса. Для привязки, вызывающей Deno.readTextFile, требуется, чтобы при запуске было предоставлено разрешение --allow-read. Веб-представление не может расширить разрешения среды выполнения с помощью привязок.
Обычно настольные приложения запускаются с широкими разрешениями, встроенными в скомпилированный бинарный файл (deno desktop в настоящее время не запрашивает отдельного разрешения во время выполнения). Если вы предоставляете привязки, работающие с файловой системой или сетью, проверяйте входные данные так же тщательно, как и в любом коде, пересекающем границу доверия.
Привязки для каждого окна
Привязки задаются отдельно для каждого окна. Привязка, зарегистрированная в winA, недоступна из веб-представления winB. Чтобы использовать привязку в нескольких окнах, зарегистрируйте её в каждом из них:
function bindShared(win: Deno.BrowserWindow) {
win.bind("now", () => Date.now());
win.bind("readSettings", readSettings);
}
const main = new Deno.BrowserWindow(); // adopts the startup window
bindShared(main);
const settings = new Deno.BrowserWindow();
bindShared(settings);
Типобезопасность
Встроенного моста типов между win.bind() на стороне Deno и bindings.<name>() на стороне веб-представления нет. Эти стороны работают в отдельных областях видимости JS.
Небольшой общий файл деклараций типов позволит описать обе стороны:
export interface Bindings {
readSettings(): Promise<Settings>;
saveSettings(s: Settings): Promise<void>;
now(): Promise<number>;
}
declare global {
// Make `bindings` typed in the webview.
const bindings: Bindings;
}
export interface Settings {
theme: "light" | "dark";
}
Подключите его в tsconfig веб-представления или конфигурации проекта Deno и используйте один и тот же интерфейс Bindings для проверки типов вызовов win.bind. Несоответствия между регистрацией и декларацией будут обнаружены при компиляции на стороне Deno.
Переход с Electron
Если вы переходите с ipcMain.handle('channel', handler) / ipcRenderer.invoke('channel', ...) в Electron, принцип работы остаётся тем же:
| Electron | deno desktop |
|---|---|
ipcMain.handle('channel', (e, ...args) => result) | win.bind('channel', (...args) => result) |
ipcRenderer.invoke('channel', ...args) | bindings.channel(...args) |
contextBridge.exposeInMainWorld('api', {...}) | Не требуется: bindings доступен по умолчанию. |
У объекта event, который Electron передаёт первым аргументом, нет аналога, поскольку отдельного процесса, которому можно было бы приписать вызов, не существует. Контекст каждого окна связан с объектом win, в котором вы зарегистрировали привязку.
Последнее обновление:
© 2018–2025 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/desktop/bindings