Использование канальной передачи сообщений
Примечание: Эта функция доступна в Потоках выполнения JavaScript.
API канальной передачи сообщений позволяет двум отдельным скриптам, выполняющимся в разных контекстах просмотра, прикреплённых к одному документу (например, два элемента <iframe>, основной документ и одиночный <iframe>, или два документа через SharedWorker) обмениваться сообщениями напрямую через двунаправленные каналы (или трубы) с портом на каждом конце.
В этой статье мы рассмотрим основы использования этой технологии.
Сферы применения
Канальная передача сообщений полезна в основном в тех случаях, когда у вас есть социальный сайт, который встраивает возможности других сайтов в свой главный интерфейс через фреймы, такие как игры, адресные книги или проигрыватель аудио с персонализированным выбором музыки. Когда эти компоненты действуют как автономные единицы, всё нормально, но сложность возникает, когда вам нужна взаимосвязь между основным сайтом и элементами <iframe>, или между разными элементами <iframe>. Например, что если вы захотите добавить контакт в адресную книгу с основного сайта, добавить высокие баллы из игры в свой профиль, или добавить новые фоновые музыкальные композиции из проигрывателя в игру? Такие вещи не так легко сделать с использованием обычных веб-технологий, из-за используемых веб-моделей безопасности. Вам нужно подумать о том, доверяют ли источники друг другу, и как передаются сообщения.
Каналы сообщений, с другой стороны, могут обеспечить безопасный канал, который позволит передавать данные между разными контекстами просмотра.
Примечание: Для получения дополнительной информации и идей, раздел Порты в качестве основы модели объектных возможностей в веб-среде спецификации будет полезен для чтения.
Простые примеры
Чтобы помочь вам начать, мы опубликовали несколько демо-версий на GitHub. Во-первых, ознакомьтесь с нашей демо-версией канальной передачи сообщений (запустить её онлайн), которая демонстрирует очень простую передачу одного сообщения между страницей и встроенным <iframe>.
Во-вторых, посмотрите нашу демо-версию с множественными сообщениями (запустить её онлайн), которая демонстрирует немного более сложную настройку, позволяющую отправлять несколько сообщений между основной страницей и IFrame.
В этой статье мы будем фокусироваться на последнем примере, который выглядит так:
Создание канала
На основной странице демо-версии у нас простая форма с текстовым полем для ввода сообщений, которые будут отправлены в <iframe>. Также у нас есть абзац, который мы будем использовать позднее для отображения подтверждающих сообщений, которые мы получим обратно от <iframe>.
const input = document.getElementById("message-input");
const output = document.getElementById("message-output");
const button = document.querySelector("button");
const iframe = document.querySelector("iframe");
const channel = new MessageChannel();
const port1 = channel.port1;
// Wait for the iframe to load
iframe.addEventListener("load", onLoad);
function onLoad() {
// Listen for button clicks
button.addEventListener("click", onClick);
// Listen for messages on port1
port1.onmessage = onMessage;
// Transfer port2 to the iframe
iframe.contentWindow.postMessage("init", "*", [channel.port2]);
}
// Post a message on port1 when the button is clicked
function onClick(e) {
e.preventDefault();
port1.postMessage(input.value);
}
// Handle messages received on port1
function onMessage(e) {
output.innerHTML = e.data;
input.value = "";
}
Мы начинаем с создания нового канала сообщений, используя конструктор MessageChannel().
Когда IFrame загрузится, мы регистрируем обработчик onclick для нашей кнопки и обработчик onmessage для MessageChannel.port1. Наконец, мы передаём MessageChannel.port2 в IFrame, используя метод window.postMessage.
Давайте разберёмся, как работает строка iframe.contentWindow.postMessage более подробно. Она принимает три аргумента:
- Отправляемое сообщение. Для первоначальной передачи порта это сообщение может быть пустой строкой, но в этом примере оно установлено на
'init'. - Источник, которому должно быть отправлено сообщение.
*означает «любой источник». - Объект, владение которым передаётся принимающему контексту просмотра. В данном случае, мы передаём
MessageChannel.port2в IFrame, чтобы он мог использоваться для связи с основной страницей.
При нажатии на нашу кнопку, мы предотвращаем стандартную отправку формы, а затем отправляем значение, введённое в наше текстовое поле, в IFrame через MessageChannel.
Получение порта и сообщения во фрейме
В элементах <iframe> у нас есть следующий JavaScript:
const list = document.querySelector("ul");
let port2;
// Listen for the initial port transfer message
window.addEventListener("message", initPort);
// Setup the transferred port
function initPort(e) {
port2 = e.ports[0];
port2.onmessage = onMessage;
}
// Handle messages received on port2
function onMessage(e) {
const listItem = document.createElement("li");
listItem.textContent = e.data;
list.appendChild(listItem);
port2.postMessage(`Message received by IFrame: "${e.data}"`);
}
Когда первоначальное сообщение получено с основной страницы через метод window.postMessage, выполняется функция initPort. Это сохраняет переданный порт и регистрирует обработчик onmessage, который будет вызываться каждый раз, когда сообщение передаётся через наш MessageChannel.
Когда сообщение получено с основной страницы, мы создаём элемент списка и вставляем его в неупорядоченный список, устанавливая значение textContent элемента списка равным атрибуту data события (в нём содержится фактическое сообщение).
Далее, мы отправляем подтверждающее сообщение обратно на главную страницу через канал сообщений, вызвав MessagePort.postMessage у MessageChannel.port2, который был первоначально передан во фрейм.
Получение подтверждения на основной странице
Вернёмся к основной странице и рассмотрим функцию обработчика onmessage.
// Handle messages received on port1
function onMessage(e) {
output.innerHTML = e.data;
input.value = "";
}
Когда подтверждающее сообщение получено обратно от IFrame о том, что исходное сообщение было успешно получено, это выводит подтверждение в абзац и очищает текстовое поле, чтобы можно было отправить следующее сообщение.
Спецификации
| Спецификация |
|---|
| HTML # каналы-сообщений |
| HTML # порты-сообщений |
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
Using_channel_messaging |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
close |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
message_event |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11.5 | 4.2 | 1.0 | ≤37 |
messageerror_event |
60 | 18 | 57 | 47 | 16.4 | 60 | 57 | 47 | 16.4 | 8.0 | 60 |
postMessage |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
start |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
worker_support |
4 | 12 | 41 | ≤15 | 5 | 18 | 41 | ≤14 | 4.2 | 1.0 | ≤37 |
| Рабочий стол | Мобильный | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | WebView Android | |
MessageChannel |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
Using_channel_messaging |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
port1 |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
port2 |
2 | 12 | 41 | 10.6 | 5 | 18 | 41 | 11 | 4.2 | 1.0 | 4.4 |
api.КаналСообщений
Таблицы BCD загружаются только в браузере
api.ПортСообщений
Таблицы BCD загружаются только в браузере
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging