MessageEventTarget mixin
(四)9.4.4 Message ports
(五)9.4.5 Ports and garbage collection
(三)9.5 Broadcasting to other browsing contexts
postMessage() API can be used as a tracking
vector.
iframe element that contains document B,
and script in document A calls postMessage() on the
Window object of document B, then a message event will be fired on that object,
marked as originating from the Window of document A. The script in document A might
look like:
var o= document. getElementsByTagName( 'iframe' )[ 0 ]; o. contentWindow. postMessage( 'Hello world' , 'https://b.example.org/' );
To register an event handler for incoming events, the script would use addEventListener() (or similar mechanisms). For example, the script in document B
might look like:
window. addEventListener( 'message' , receiver, false );
function receiver( e) {
if ( e. origin == 'https://example.com' ) {
if ( e. data == 'Hello world' ) { e. source. postMessage( 'Hello' , e. origin);
} else {
alert( e. data);
}
}
}
This script first checks the domain is the expected domain, and then looks at the message,
which it either displays to the user, or responds to by sending a message back to the document
which sent the message in the first place.
origin attribute to
ensure that messages are only accepted from domains that they expect to receive messages from.
Otherwise, bugs in the author's message handling code could be exploited by hostile sites.
Furthermore, even after checking the origin
attribute, authors should also check that the data in question is of the expected format.
Otherwise, if the source of the event has been attacked using a cross-site scripting flaw, further
unchecked processing of information sent using the postMessage() method could result in the attack being
propagated into the receiver.
Authors should not use the wildcard keyword (*) in the targetOrigin
argument in messages that contain any confidential information, as otherwise there is no way to
guarantee that the message is only delivered to the recipient to which it was intended.
dispatchEvent() or otherwise) to objects in
other origins (those that are not the same).
Implementers are urged to take extra care in the implementation of this feature.
It allows authors to transmit information from one domain to another domain, which is normally
disallowed for security reasons. It also requires that UAs be careful to allow access to certain
properties but not others.
window.postMessage(message [, options ])
Window/postMessage
Support in all current engines.
Firefox3+Safari4+Chrome2+Date objects, etc.),
and can contain certain data objects such as File Blob,
FileList, and ArrayBuffer objects.
Objects listed in the transfer member
of options are transferred, not just cloned, meaning that they are no longer usable
on the sending side.
A target origin can be specified using the targetOrigin member of
options. If not provided, it defaults to "/". This default
restricts the message to same-origin targets only.
If the origin of the target window doesn't match the given target origin, the message is
discarded, to avoid information leakage. To send the message to the target regardless of origin,
set the target origin to "*".
Throws a "DataCloneError" DOMExceptioniftransfer array contains duplicate objects or if message could not be
cloned.
window.postMessage(message, targetOrigin [, transfer ])
This is an alternate version of postMessage() where the target origin is specified
as a parameter. Calling window.postMessage(message, target, transfer) is
equivalent to window.postMessage(message, {targetOrigin,
transfer}).
When posting a message to a Window of a browsing context
that has just been navigated to a new Document is likely to result in the message not
receiving its intended recipient: the scripts in the target browsing context have to
have had time to set up listeners for the messages. Thus, for instance, in situations where a
message is to be sent to the Window of newly created child iframe,
authors are advised to have the child Document post a message to their parent
announcing their readiness to receive messages, and for the parent to wait for this message before
beginning posting messages.
The window post message steps, given a targetWindow, message,
and options, are as follows:
Let targetRealmbetargetWindow's realm.
Let incumbentSettings be the incumbent settings object.
Let targetOriginbeoptions["targetOrigin"].
IftargetOrigin is a single U+002F SOLIDUS character (/), then set
targetOrigintoincumbentSettings's origin.
Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*),
then:
Let parsedURL be the result of running the URL parserontargetOrigin.
IfparsedURL is failure, then throw a "SyntaxError"
DOMException.
Set targetOrigintoparsedURL's origin.
Let transferbeoptions["transfer"].
Let serializeWithTransferResultbeStructuredSerializeWithTransfer(message, transfer). Rethrow
any exceptions.
Queue a global task on the posted message task source given
targetWindow to run the following steps:
If the targetOrigin argument is not a single literal U+002A ASTERISK character
(*) and targetWindow's associated
Document's origin is not
same origin with targetOrigin, then return.
Let origin be the serializationofincumbentSettings's origin.
Let source be the WindowProxy object corresponding to
incumbentSettings's global
object (aWindow object).
Let deserializeRecordbeStructuredDeserializeWithTransfer(serializeWithTransferResult,
targetRealm).
If this throws an exception, catch it, fire an
event named messageerrorattargetWindow, using MessageEvent, with the origin attribute initialized to origin and
the source attribute initialized to
source, and then return.
Let messageClonebedeserializeRecord.[[Deserialized]].
Let newPorts be a new frozen array consisting of all
MessagePort objects in deserializeRecord.[[TransferredValues]], if any,
maintaining their relative order.
Fire an event named messageattargetWindow, using
MessageEvent, with the origin
attribute initialized to origin, the source attribute initialized to source, the
data attribute initialized to
messageClone, and the ports attribute
initialized to newPorts.
The Window interface's postMessage(message,
options) method steps are to run the window post message
steps given this, message, and options.
The Window interface's postMessage(message, targetOrigin,
transfer) method steps are to run the window post message
steps given this, message, and «[ "targetOrigin" →
targetOrigin, "transfer"
→ transfer ]».
MessageChannel()
constructor is called:
var channel = new MessageChannel();
One of the ports is kept as the local port, and the other port is sent to the remote code, e.g.
using postMessage():
otherWindow. postMessage( 'hello' , 'https://example.com' , [ channel. port2]);
To send messages, the postMessage() method on
the port is used:
channel. port1. postMessage( 'hello' );
To receive messages, one listens to message events:
channel. port1. onmessage = handleMessage;
function handleMessage( event) {
// message is in event.data
// ...
}
Data sent on a port can be structured data; for example here an array of strings is passed on a
MessagePort:
port1. postMessage([ 'hello' , 'world' ]);
MessagePorts. This allows the libraries to later be hosted in different frames, or
in Worker objects, without any change to the APIs.
< script src = "contacts.js" ></ script > <!-- exposes a contacts object -->
< script src = "compose-mail.js" ></ script > <!-- exposes a composer object -->
< script >
var channel = new MessageChannel();
composer. addContactsProvider( channel. port1);
contacts. registerConsumer( channel. port2);
</ script >
Here's what the "addContactsProvider()" function's implementation could look like:
function addContactsProvider( port) {
port. onmessage = function ( event) {
switch ( event. data. messageType) {
case 'search-result' : handleSearchResult( event. data. results); break ;
case 'search-done' : handleSearchDone(); break ;
case 'search-error' : handleSearchError( event. data. message); break ;
// ...
}
};
};
Alternatively, it could be implemented as follows:
function addContactsProvider( port) {
port. addEventListener( 'message' , function ( event) {
if ( event. data. messageType == 'search-result' )
handleSearchResult( event. data. results);
});
port. addEventListener( 'message' , function ( event) {
if ( event. data. messageType == 'search-done' )
handleSearchDone();
});
port. addEventListener( 'message' , function ( event) {
if ( event. data. messageType == 'search-error' )
handleSearchError( event. data. message);
});
// ...
port. start();
};
The key difference is that when using addEventListener(), the start() method must also be invoked. When using onmessage, the call to start() is implied.
The start() method, whether called explicitly or
implicitly (by setting onmessage),
starts the flow of messages: messages posted on message ports are initially paused, so that they
don't get dropped on the floor before the script has had a chance to set up its handlers.
iframe
the user's email contacts provider (an address book site, from a second origin), and in a second
iframe a game (from a third origin). The outer social site and the game in the second
iframe cannot access anything inside the first iframe; together they can
only:
Navigate the iframe to a new URL, such as the same
URL but with a different fragment,
causing the Window in the iframe to receive a hashchange event.
Resize the iframe, causing the Window in the iframe
to receive a resize event.
Send a message event to the Window in the
iframe using the window.postMessage()
API.
The contacts provider can use these methods, most particularly the third one, to provide an API
that can be accessed by other origins to manipulate the user's address book. For example, it could
respond to a message﹃add-contact Guillaume Tell
<tell@pomme.example.net>﹄by adding the given person and email address to the user's
address book.
To avoid any site on the web being able to manipulate the user's contacts, the contacts
provider might only allow certain trusted sites, such as the social site, to do this.
Now suppose the game wanted to add a contact to the user's address book, and that the social
site was willing to allow it to do so on its behalf, essentially "sharing" the trust that the
contacts provider had with the social site. There are several ways it could do this; most simply,
it could just proxy messages between the game site and the contacts site. However, this solution
has a number of difficulties: it requires the social site to either completely trust the game site
not to abuse the privilege, or it requires that the social site verify each request to make sure
it's not a request that it doesn't want to allow (such as adding multiple contacts, reading the
contacts, or deleting them); it also requires some additional complexity if there's ever the
possibility of multiple games simultaneously trying to interact with the contacts provider.
Using message channels and MessagePort objects, however, all of these problems can
go away. When the game tells the social site that it wants to add a contact, the social site can
ask the contacts provider not for it to add a contact, but for the capability to add a
single contact. The contacts provider then creates a pair of MessagePort objects, and
sends one of them back to the social site, who forwards it on to the game. The game and the
contacts provider then have a direct connection, and the contacts provider knows to only honor a
single "add contact" request, nothing else. In other words, the game has been granted the
capability to add a single contact.
XMLHttpRequest objects in the
service's iframe, an evolution of the service might instead want to use a shared worker with a single WebSocket connection.
If the initial design used MessagePort objects to grant capabilities, or even just
to allow multiple simultaneous independent sessions, the service implementation can switch from
the XMLHttpRequests-in-each-iframe model to the
shared-WebSocket model without changing the API at all: the ports on the service
provider side can all be forwarded to the shared worker without it affecting the users of the API
in the slightest.
[Exposed =(Window ,Worker )]
interface MessageChannel {
constructor ();
readonly attribute MessagePort port1 ;
readonly attribute MessagePort port2 ;
};
channel = new MessageChannel()
N
MessageChannel/MessageChannel
Support in all current engines.
Firefox41+Safari5+Chrome2+MessageChannel object with two new MessagePort
objects.
channel.port1
N
MessageChannel/port1
Support in all current engines.
Firefox41+Safari5+Chrome2+MessagePort object.
channel.port2
N
MessageChannel/port2
Support in all current engines.
Firefox41+Safari5+Chrome2+MessagePort object.
AMessageChannel object has an associated port 1 and an associated
port 2, both MessagePort objects.
The new MessageChannel() constructor steps
are:
Set this's port 1 to a new
MessagePortinthis's relevant
realm.
Set this's port 2 to a new
MessagePortinthis's relevant
realm.
Entangle this's port 1 and this's
port 2.
The port1 getter steps are to return
this's port 1.
The port2 getter steps are to return
this's port 2.
MessageEventTarget mixin
interface mixin MessageEventTarget {
attribute EventHandler onmessage ;
attribute EventHandler onmessageerror ;
};
The following are the event handlers (and their corresponding event handler event types) that must be supported,
as event handler IDL attributes, by objects implementing the
MessageEventTarget interface:
| Event handler | Event handler event type |
|---|---|
onmessage Support in all current engines.
Firefox41+Safari5+Chrome2+ Opera10.6+Edge79+ Edge (Legacy)12+Internet Explorer10+ Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android11.5+ DedicatedWorkerGlobalScope/message_event Support in all current engines.
Firefox3.5+Safari4+Chrome4+ Opera10.6+Edge79+ Edge (Legacy)12+Internet Explorer10+ Firefox Android?Safari iOS5+Chrome Android?WebView Android37+Samsung Internet?Opera Android11.5+ | message
|
onmessageerror MessagePort/messageerror_event Support in all current engines.
Firefox57+Safari16.4+Chrome60+ Opera?Edge79+ Edge (Legacy)18Internet ExplorerNo Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+ DedicatedWorkerGlobalScope/messageerror_event Support in all current engines.
Firefox57+Safari16.4+Chrome60+ Opera?Edge79+ Edge (Legacy)18Internet ExplorerNo Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+ | messageerror
|
Support in all current engines.
Each channel has two message ports. Data sent through one port is received by the other port, and vice versa.
[Exposed =(Window ,Worker ,AudioWorklet ), Transferable ]
interface MessagePort : EventTarget {
undefined postMessage (any message , sequence <object > transfer );
undefined postMessage (any message , optional StructuredSerializeOptions options = {});
undefined start ();
undefined close ();
// event handlers
attribute EventHandler onclose ;
};
MessagePort includes MessageEventTarget ;
dictionary StructuredSerializeOptions {
sequence <object > transfer = [];
};
port.postMessage(message [, transfer])Support in all current engines.
port.postMessage(message [, { transfer }])Posts a message through the channel. Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
Throws a "DataCloneError" DOMExceptioniftransfer contains duplicate objects or port, or if message
could not be cloned.
port.start()Support in all current engines.
Begins dispatching messages received on the port.
port.close()Support in all current engines.
Disconnects the port, so that it is no longer active.
Each MessagePort object has a message event target (aMessageEventTarget), to which the message and messageerror events are dispatched. Unless otherwise
specified, it defaults to the MessagePort object itself.
Each MessagePort object can be entangled with another (a symmetric relationship).
Each MessagePort object also has a task source called the port
message queue, initially empty. A port message queue can be enabled or
disabled, and is initially disabled. Once enabled, a port can never be disabled again (though
messages in the queue can get moved to another queue or removed altogether, which has much the
same effect). A MessagePort also has a has been shipped flag, which must
initially be false.
When a port's port message queue is enabled, the event loop must use
it as one of its task sources. When a port's relevant
global object is a Window, all tasks queued on its port message queue must be associated with
the port's relevant global object's associated
Document.
If the document is fully active, but the event listeners were all created in the context of documents that are not fully active, then the messages will not be received unless and until the documents become fully active again.
Each event loop has a task source called the unshipped port
message queue. This is a virtual task source: it must act as if it contained
the tasks of each port message queue of each
MessagePort whose has been shipped flag is false, whose port
message queue is enabled, and whose relevant agent's event loop is that event loop, in the order
in which they were added to their respective task source. When a task would be removed from the unshipped port message
queue, it must instead be removed from its port message queue.
When a MessagePort's has been shipped flag is false, its port
message queue must be ignored for the purposes of the event loop. (The
unshipped port message queue is used instead.)
The has been shipped flag is set to true when a port, its twin, or
the object it was cloned from, is or has been transferred. When a MessagePort's
has been shipped flag is true, its port message queue acts as a
first-class task source, unaffected to any unshipped port message
queue.
When the user agent is to entangle two MessagePort objects, it must run
the following steps:
If one of the ports is already entangled, then disentangle it and the port that it was entangled with.
If those two previously entangled ports were the two ports of a
MessageChannel object, then that MessageChannel object no longer
represents an actual channel: the two ports in that object are no longer entangled.
Associate the two ports to be entangled, so that they form the two parts of a new channel.
(There is no MessageChannel object that represents this channel.)
Two ports A and B that have gone through this step are now said to be entangled; one is entangled to the other, and vice versa.
While this specification describes this process as instantaneous, implementations are more likely to implement it via message passing. As with all algorithms, the key is "merely" that the end result be indistinguishable, in a black-box sense, from the specification.
The disentangle steps, given a MessagePort initiatorPort
which initiates disentangling, are as follows:
Let otherPort be the MessagePort which initiatorPort
was entangled with.
Assert: otherPort exists.
Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
Fire an event named closeatotherPort.
The close event will be fired even if the port is not
explicitly closed. The cases where this event is dispatched are:
close() method was called;Document was destroyed; orMessagePort was garbage
collected.
We only dispatch the event on otherPort because initiatorPort explicitly
triggered the close, its Document no longer exists, or it was already garbage
collected, as described above.
MessagePort objects are transferable
objects. Their transfer steps, given value and
dataHolder, are:
Set value's has been shipped flag to true.
Set dataHolder.[[PortMessageQueue]] to value's port message queue.
Ifvalue is entangled with another port remotePort, then:
Set remotePort's has been shipped flag to true.
Set dataHolder.[[RemotePort]] to remotePort.
Otherwise, set dataHolder.[[RemotePort]] to null.
Their transfer-receiving steps, given dataHolder and value, are:
Set value's has been shipped flag to true.
Move all the tasks that are to fire message events in dataHolder.[[PortMessageQueue]] to the
port message queueofvalue, if any, leaving value's
port message queue in its initial disabled state, and, if value's
relevant global object is a Window, associating the moved tasks with value's relevant global object's
associated Document.
IfdataHolder.[[RemotePort]] is not null, then entangle dataHolder.[[RemotePort]] and value. (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.)
The message port post message steps, given sourcePort, targetPort, message, and options are as follows:
Let transferbeoptions["transfer"].
Iftransfer contains
sourcePort, then throw a "DataCloneError"
DOMException.
Let doomed be false.
IftargetPort is not null and transfer contains targetPort, then set doomed to true and optionally report to a developer console that the target port was posted to itself, causing the communication channel to be lost.
Let serializeWithTransferResultbeStructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
IftargetPort is null, or if doomed is true, then return.
Add a task that runs the following steps to the port message queueoftargetPort:
Let finalTargetPort be the MessagePort in whose port message
queue the task now finds itself.
This can be different from targetPort, if targetPort itself was transferred and thus all its tasks moved along with it.
Let messageEventTargetbefinalTargetPort's message event target.
Let targetRealmbefinalTargetPort's relevant realm.
Let deserializeRecordbeStructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).
If this throws an exception, catch it, fire an
event named messageerroratmessageEventTarget, using MessageEvent, and then return.
Let messageClonebedeserializeRecord.[[Deserialized]].
Let newPorts be a new frozen array consisting of all
MessagePort objects in deserializeRecord.[[TransferredValues]], if any,
maintaining their relative order.
Fire an event named messageatmessageEventTarget, using
MessageEvent, with the data attribute
initialized to messageClone and the ports attribute initialized to
newPorts.
The postMessage(message,
options) method steps are:
Let targetPort be the port with which this is entangled, if any; otherwise let it be null.
Run the message port post message steps providing this, targetPort, message and options.
The postMessage(message,
transfer) method steps are:
Let targetPort be the port with which this is entangled, if any; otherwise let it be null.
Let options be «[ "transfer" → transfer
]».
Run the message port post message steps providing this, targetPort, message and options.
The start()
method steps are to enable this's port message queue, if it is not
already enabled.
The close()
method steps are:
Set this's [[Detached]] internal slot value to true.
Ifthis is entangled, disentangle it.
The following are the event handlers (and their corresponding event handler event types) that must be supported,
as event handler IDL attributes, by all objects implementing the
MessagePort interface:
| Event handler | Event handler event type |
|---|---|
onclose | close
|
The first time a MessagePort object's onmessage IDL attribute is set, the port's
port message queue must be enabled, as if the start() method had been called.
When a MessagePort object o is garbage collected, if o is
entangled, then the user agent must disentangle
o.
When a MessagePort object o is entangled and messageormessageerror
event listener is registered, user agents must act as if o's entangled
MessagePort object has a strong reference to o.
Furthermore, a MessagePort object must not be garbage collected while there
exists an event referenced by a task in a task
queue that is to be dispatched on that MessagePort object, or while the
MessagePort object's port message queue is enabled and not empty.
Thus, a message port can be received, given an event listener, and then forgotten, and so long as that event listener could receive a message, the channel will be maintained.
Of course, if this was to occur on both sides of the channel, then both ports could be garbage collected, since they would not be reachable from live code, despite having a strong reference to each other. However, if a message port has a pending message, it is not garbage collected.
Authors are strongly encouraged to explicitly close MessagePort
objects to disentangle them, so that their resources can be recollected. Creating many
MessagePort objects and discarding them without closing them can lead to high
transient memory usage since garbage collection is not necessarily performed promptly, especially
for MessagePorts where garbage collection can involve cross-process coordination.
Support in all current engines.
Support in all current engines.
Pages on a single origin opened by the same user in the same user agent but in different unrelated browsing contexts sometimes need to send notifications to each other, for example "hey, the user logged in over here, check your credentials again".
For elaborate cases, e.g. to manage locking of shared state, to manage synchronization of
resources between a server and multiple local clients, to share a WebSocket
connection with a remote host, and so forth, shared workers are
the most appropriate solution.
For simple cases, though, where a shared worker would be an unreasonable overhead, authors can use the simple channel-based broadcast mechanism described in this section.
[Exposed =(Window ,Worker )]
interface BroadcastChannel : EventTarget {
constructor (DOMString name );
readonly attribute DOMString name ;
undefined postMessage (any message );
undefined close ();
attribute EventHandler onmessage ;
attribute EventHandler onmessageerror ;
};
broadcastChannel = new BroadcastChannel(name)BroadcastChannel/BroadcastChannel
Support in all current engines.
Returns a new BroadcastChannel object via which messages for the given channel
name can be sent and received.
broadcastChannel.nameSupport in all current engines.
Returns the channel name (as passed to the constructor).
broadcastChannel.postMessage(message)Support in all current engines.
Sends the given message to other BroadcastChannel objects set up for this
channel. Messages can be structured objects, e.g. nested objects and arrays.
broadcastChannel.close()Support in all current engines.
Closes the BroadcastChannel object, opening it up to garbage
collection.
ABroadcastChannel object has a channel name and a closed flag.
The new BroadcastChannel(name)
constructor steps are:
Set this's channel nametoname.
Set this's closed flag to false.
The name getter steps are to return
this's channel name.
ABroadcastChannel object is said to be eligible for messaging when
its relevant global object is either:
aWindow object whose associated
Documentisfully active, or
aWorkerGlobalScope object whose closing flag is false and is not suspendable.
The postMessage(message) method
steps are:
Ifthis is not eligible for messaging, then return.
Ifthis's closed flag
is true, then throw an "InvalidStateError"
DOMException.
Let serializedbeStructuredSerialize(message). Rethrow any exceptions.
Let sourceOriginbethis's relevant settings object's origin.
Let sourceStorageKey be the result of running obtain a storage key for non-storage purposes with this's relevant settings object.
Let destinations be a list of BroadcastChannel objects that
match the following criteria:
They are eligible for messaging.
The result of running obtain a storage key for non-storage purposes with their relevant settings object equals sourceStorageKey.
Their channel name is this's channel name.
Remove source from destinations.
Sort destinations such that all BroadcastChannel objects whose
relevant agents are the same are sorted in creation order,
oldest first. (This does not define a complete ordering. Within this constraint, user agents may
sort the list in any implementation-defined manner.)
For each destinationindestinations, queue a global task on the DOM manipulation task source given destination's relevant global object to perform the following steps:
Ifdestination's closed flag is true, then abort these steps.
Let targetRealmbedestination's relevant realm.
Let databeStructuredDeserialize(serialized, targetRealm).
If this throws an exception, catch it, fire an
event named messageerroratdestination, using MessageEvent, with the origin attribute initialized to the serializationofsourceOrigin, and then
abort these steps.
Fire an event named messageatdestination, using
MessageEvent, with the data attribute
initialized to data and the origin
attribute initialized to the serializationofsourceOrigin.
While a BroadcastChannel object whose closed flag is false has an event listener
registered for messageormessageerror events, there must be a strong reference from the
BroadcastChannel object's relevant global object to the
BroadcastChannel object itself.
The close() method steps are to set
this's closed flag to true.
Authors are strongly encouraged to explicitly close BroadcastChannel
objects when they are no longer needed, so that they can be garbage collected. Creating many
BroadcastChannel objects and discarding them while leaving them with an event
listener and without closing them can lead to an apparent memory leak, since the objects will
continue to live for as long as they have an event listener (or until their page or worker is
closed).
The following are the event handlers (and their corresponding event handler event types) that must be supported,
as event handler IDL attributes, by all objects implementing the
BroadcastChannel interface:
| Event handler | Event handler event type |
|---|---|
onmessage BroadcastChannel/message_event Support in all current engines.
Firefox38+Safari15.4+Chrome54+ Opera?Edge79+ Edge (Legacy)?Internet ExplorerNo Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? | message
|
onmessageerror BroadcastChannel/messageerror_event Support in all current engines.
Firefox57+Safari15.4+Chrome60+ Opera?Edge79+ Edge (Legacy)?Internet ExplorerNo Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+ | messageerror
|
Suppose a page wants to know when the user logs out, even when the user does so from another tab at the same site:
var authChannel = new BroadcastChannel( 'auth' );
authChannel. onmessage = function ( event) {
if ( event. data == 'logout' )
showLogout();
}
function logoutRequested() {
// called when the user asks us to log them out
doLogout();
showLogout();
authChannel. postMessage( 'logout' );
}
function doLogout() {
// actually log the user out (e.g. clearing cookies)
// ...
}
function showLogout() {
// update the UI to indicate we're logged out
// ...
}