Support: x-doc-messaging Chrome for Android 67+ Chrome 4+ iOS Safari 3.2+ UC Browser for Android 11.8+ Firefox 3+ IE (limited) 8+ Opera Mini all+ Safari 4+ Edge 12+ Samsung Internet 4+ Opera 9.5+ Android Browser 2.1+
Source: caniuse.com
Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.
While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.
This API has some privacy implications that might not be immediately obvious.
The task source for the tasks in cross-document messaging is the posted message task source .
This section is non-normative.
For
example,
if
document
A
contains
an
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.
Use of this API requires extra care to protect users from hostile entities abusing a site for their own purposes.
Authors
should
check
the
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.
Authors who accept messages from any origin are encouraged to consider the risks of a denial-of-service attack. An attacker could send a high volume of messages; if the receiving page performs expensive computation or causes network traffic to be sent for each such message, the attacker's message could be multiplied into a denial-of-service attack. Authors are encouraged to employ rate limiting (only accepting a certain number of messages per minute) to make such attacks impractical.
The
integrity
of
this
API
is
based
on
the
inability
for
scripts
of
one
origin
to
post
arbitrary
events
(using
dispatchEvent()
or
otherwise)
to
objects
in
other
origins
(those
that
are
not
the
same
).
Implementors 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.
User agents are also encouraged to consider rate-limiting message traffic between different origins , to protect naïve sites from denial-of-service attacks.
postMessage
(
message
,
targetOrigin
[,
transfer
]
)
Posts
a
message
to
the
given
window.
Messages
can
be
structured
objects,
e.g.
nested
objects
and
arrays,
can
contain
JavaScript
values
(strings,
numbers,
Date
objects,
etc),
and
can
contain
certain
data
objects
such
as
File
Blob
,
FileList
,
and
ArrayBuffer
objects.
Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
If
the
origin
of
the
target
window
doesn't
match
the
given
origin,
the
message
is
discarded,
to
avoid
information
leakage.
To
send
the
message
to
the
target
regardless
of
origin,
set
the
target
origin
to
"
*
".
To
restrict
the
message
to
same-origin
targets
only,
without
needing
to
explicitly
state
the
origin,
set
the
target
origin
to
"
/
".
Throws
a
"
DataCloneError
"
DOMException
if
transfer
array
contains
duplicate
objects
or
if
message
could
not
be
cloned.
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
postMessage(
message
,
targetOrigin
,
transfer
)
method,
when
invoked
on
a
Window
object
must
run
the
following
steps:
Let
targetWindow
be
this
Window
object.
Let targetRealm be targetWindow 's Realm .
Let incumbentSettings be the incumbent settings object .
If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to incumbentSettings 's origin .
Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:
Let parsedURL be the result of running the URL parser on targetOrigin .
If
parsedURL
is
failure,
then
throw
a
"
SyntaxError
"
DOMException
.
Set targetOrigin to parsedURL 's origin .
Let serializeWithTransferResult be StructuredSerializeWithTransfer ( message , transfer ). Rethrow any exceptions.
Queue a task on the posted message task source 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 serialization of incumbentSettings 's origin .
Let
source
be
the
WindowProxy
object's
corresponding
to
incumbentSettings
's
global
object
(a
Window
object).
Let deserializeRecord be StructuredDeserializeWithTransfer ( serializeWithTransferResult , targetRealm ).
If
this
throws
an
exception,
catch
it,
fire
an
event
named
messageerror
at
targetWindow
,
using
MessageEvent
,
with
the
origin
attribute
initialized
to
origin
and
the
source
attribute
initialized
to
source
,
and
then
return.
Let messageClone be deserializeRecord .[[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
message
at
targetWindow
,
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
.
Support: channel-messaging Chrome for Android 67+ Chrome 4+ iOS Safari 5.0+ UC Browser for Android 11.8+ Firefox 41+ IE 10+ Opera Mini None Safari 5+ Edge 12+ Samsung Internet 4+ Opera 10.6+ Android Browser 4.4+
Source: caniuse.com
This section is non-normative.
To enable independent pieces of code (e.g. running in different browsing contexts ) to communicate directly, authors can use channel messaging .
Communication channels in this mechanism are implemented as two-ways pipes, with a port at each end. Messages sent in one port are delivered at the other port, and vice-versa. Messages are delivered as DOM events, without interrupting or blocking running tasks .
To
create
a
connection
(two
"entangled"
ports),
the
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']);
This section is non-normative.
In
this
example,
two
JavaScript
libraries
are
connected
to
each
other
using
MessagePort
s.
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) {
'search-result': handleSearchResult(event.data.results); break;
'search-done': handleSearchDone(); break;
'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.
This section is non-normative.
Ports can be viewed as a way to expose limited capabilities (in the object-capability model sense) to other actors in the system. This can either be a weak capability system, where the ports are merely used as a convenient model within a particular origin, or as a strong capability model, where they are provided by one origin provider as the only mechanism by which another origin consumer can effect change in or obtain information from provider .
For
example,
consider
a
situation
in
which
a
social
Web
site
embeds
in
one
iframe
the
user's
e-mail
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:
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.
iframe
,
causing
the
Window
in
the
iframe
to
receive
a
resize
event.
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
e-mail
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.
This section is non-normative.
Continuing
the
example
from
the
previous
section,
consider
the
contacts
provider
in
particular.
While
an
initial
implementation
might
have
simply
used
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
XMLHttpRequest
s-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.
[Constructor, Exposed=(Window,Worker)]
interface MessageChannel {
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};
MessageChannel
()
Returns
a
new
MessageChannel
object
with
two
new
MessagePort
objects.
port1
Returns
the
first
MessagePort
object.
port2
Returns
the
second
MessagePort
object.
When
the
MessageChannel()
constructor
is
called,
it
must
run
the
following
algorithm:
Create
a
new
MessagePort
object
whose
owner
is
the
incumbent
settings
object
,
and
let
port1
be
that
object.
Create
a
new
MessagePort
object
whose
owner
is
the
incumbent
settings
object
,
and
let
port2
be
that
object.
Entangle the port1 and port2 objects.
Instantiate
a
new
MessageChannel
object,
and
let
channel
be
that
object.
Let
the
port1
attribute
of
the
channel
object
be
port1
.
Let
the
port2
attribute
of
the
channel
object
be
port2
.
Return channel .
The
port1
and
port2
attributes
must
return
the
values
they
were
assigned
when
the
MessageChannel
object
was
created.
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 {
void postMessage(any message, optional sequence<object> transfer = []);
void start();
void close();
// event handlers
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
};
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
"
DOMException
if
transfer
contains
duplicate
objects
or
port
,
or
if
message
could
not
be
cloned.
start
()
Begins dispatching messages received on the port.
close
()
Disconnects the port, so that it is no longer active.
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,
and
an
owner
,
which
is
a
settings
object
set
when
the
object
is
created,
as
described
below.
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 owner specifies a responsible event loop that is a browsing context event loop , all tasks queued on its port message queue must be associated with the responsible document specified by the port's owner .
If the port's owner specifies a responsible document that is fully active , but the event listeners all have scripts whose settings objects specify responsible documents that are not fully active , then the messages will be lost.
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
owner
specifies
that
event
loop
as
the
responsible
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
create
a
new
MessagePort
object
with
a
particular
environment
settings
object
as
its
owner
,
it
must
instantiate
a
new
MessagePort
object,
and
let
its
owner
be
owner
.
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.
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 .
If value 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.
Set value 's owner to value 's relevant settings object .
Move
all
the
tasks
that
are
to
fire
message
events
in
dataHolder
.[[PortMessageQueue]]
to
the
port
message
queue
of
value
,
if
any,
leaving
value
's
port
message
queue
in
its
initial
disabled
state,
and,
if
value
's
owner
specifies
a
responsible
event
loop
that
is
a
browsing
context
event
loop
,
associating
the
moved
tasks
with
the
responsible
document
specified
by
value
's
owner
.
If dataHolder .[[RemotePort]] is not null, then entangle dataHolder .[[RemotePort]] and value . (This will disentangle dataHolder .[[RemotePort]] from the original port that was transferred.)
The
postMessage(
message
,
transfer
)
method,
when
invoked
on
a
MessagePort
object,
must
run
the
following
steps:
Let
targetPort
be
the
port
with
which
this
MessagePort
is
entangled,
if
any;
otherwise
let
it
be
null.
If
transfer
contains
this
MessagePort
,
then
throw
a
"
DataCloneError
"
DOMException
.
Let doomed be false.
If targetPort 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 serializeWithTransferResult be StructuredSerializeWithTransfer ( message , transfer ). Rethrow any exceptions.
If targetPort is null, or if doomed is true, then return.
Add a task that runs the following steps to the port message queue of targetPort :
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 targetRealm be finalTargetPort 's relevant Realm .
Let deserializeRecord be StructuredDeserializeWithTransfer ( serializeWithTransferResult , targetRealm ).
If
this
throws
an
exception,
catch
it,
fire
an
event
named
messageerror
at
finalTargetPort
,
using
MessageEvent
,
and
then
return.
Let messageClone be deserializeRecord .[[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
message
at
finalTargetPort
,
using
MessageEvent
,
with
the
data
attribute
initialized
to
messageClone
and
the
ports
attribute
initialized
to
newPorts
.
The
start()
method,
when
invoked,
must
enable
this
MessagePort
object's
port
message
queue
,
if
it
is
not
already
enabled.
The
close()
method,
when
invoked,
must
run
these
steps:
Set
this
MessagePort
object's
[[Detached]]
internal
slot
value
to
true.
If
this
MessagePort
object
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 |
---|---|
onmessage
|
message
|
onmessageerror
|
messageerror
|
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.
This section is non-normative.
Broadcasting
to
many
ports
is
in
principle
relatively
simple:
keep
an
array
of
MessagePort
objects
to
send
messages
to,
and
iterate
through
the
array
to
send
a
message.
However,
this
has
one
rather
unfortunate
effect:
it
prevents
the
ports
from
being
garbage
collected,
even
if
the
other
side
has
gone
away.
To
avoid
this
problem,
implement
a
simple
protocol
whereby
the
other
side
acknowledges
it
still
exists.
If
it
doesn't
do
so
after
a
certain
amount
of
time,
assume
it's
gone,
close
the
MessagePort
object,
and
let
it
be
garbage
collected.
When
a
MessagePort
object
o
is
entangled,
user
agents
must
either
act
as
if
o
's
entangled
MessagePort
object
has
a
strong
reference
to
o
,
or
as
if
the
global
object
specified
by
o
's
owner
has
a
strong
reference
to
o
.
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.
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.
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
MessagePort
s
where
garbage
collection
can
involve
cross-process
coordination.
Support: broadcastchannel Chrome for Android 67+ Chrome 54+ iOS Safari None UC Browser for Android 11.8+ Firefox 38+ IE None Opera Mini None Safari None Edge None Samsung Internet 7.2+ Opera 41+ Android Browser 67+
Source: caniuse.com
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.
[Constructor(DOMString name), Exposed=(Window,Worker)]
interface BroadcastChannel : EventTarget {
readonly attribute DOMString name;
void postMessage(any message);
void close();
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
};
BroadcastChannel
(
name
)
Returns
a
new
BroadcastChannel
object
via
which
messages
for
the
given
channel
name
can
be
sent
and
received.
name
Returns the channel name (as passed to the constructor).
postMessage
(
message
)
Sends
the
given
message
to
other
BroadcastChannel
objects
set
up
for
this
channel.
Messages
can
be
structured
objects,
e.g.
nested
objects
and
arrays.
close
()
Closes
the
BroadcastChannel
object,
opening
it
up
to
garbage
collection.
A
BroadcastChannel
object
has
a
channel
name
,
a
BroadcastChannel
settings
object
,
and
a
closed
flag
.
The
BroadcastChannel()
constructor,
when
invoked,
must
create
and
return
a
BroadcastChannel
object
whose
channel
name
is
the
constructor's
first
argument,
whose
BroadcastChannel
settings
object
is
the
incumbent
settings
object
,
and
whose
closed
flag
is
false.
The
name
attribute
must
return
the
channel
name
.
The
postMessage(
message
)
method,
when
invoked
on
a
BroadcastChannel
object,
must
run
the
following
steps:
Let
source
be
this
BroadcastChannel
.
Let
sourceSettings
be
source
's
BroadcastChannel
settings
object
.
If
source
's
closed
flag
is
true,
then
throw
an
"
InvalidStateError
"
DOMException
.
Let sourceChannel be source 's channel name .
Let targetRealm be a user-agent defined Realm.
Let serialized be StructuredSerialize ( message ). Rethrow any exceptions.
Let
destinations
be
a
list
of
BroadcastChannel
objects
that
match
the
following
criteria:
Their
BroadcastChannel
settings
object
specifies
either:
a
global
object
that
is
a
Window
object
and
a
responsible
document
that
is
fully
active
,
or
a
global
object
that
is
a
WorkerGlobalScope
object
whose
closing
flag
is
false
and
whose
worker
is
not
a
suspendable
worker
.
Their
BroadcastChannel
settings
object
's
origin
is
same
origin
with
sourceSettings
's
origin
.
Their channel name is a case-sensitive match for sourceChannel .
Their closed flag is false.
Remove source from destinations .
Sort
destinations
such
that
all
BroadcastChannel
objects
whose
BroadcastChannel
settings
objects
specify
the
same
responsible
event
loop
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
user-agent
defined
manner.)
For
each
BroadcastChannel
object
destination
in
destinations
,
queue
a
task
that
runs
the
following
steps:
Let targetRealm be destination 's relevant Realm .
Let data be StructuredDeserialize ( serialized , targetRealm ).
If
this
throws
an
exception,
catch
it,
fire
an
event
named
messageerror
at
destination
,
using
MessageEvent
,
with
the
origin
attribute
initialized
to
the
serialization
of
sourceSettings
's
origin
,
and
then
return.
Fire
an
event
named
message
at
destination
,
using
MessageEvent
,
with
the
data
attribute
initialized
to
data
and
the
origin
attribute
initialized
to
the
serialization
of
sourceSettings
's
origin
.
The
tasks
must
use
the
DOM
manipulation
task
source
,
and,
for
those
where
the
event
loop
specified
by
the
target
BroadcastChannel
object's
BroadcastChannel
settings
object
is
a
browsing
context
event
loop
,
must
be
associated
with
the
responsible
document
specified
by
that
target
BroadcastChannel
object's
BroadcastChannel
settings
object
.
While
a
BroadcastChannel
object
whose
closed
flag
is
false
has
an
event
listener
registered
for
message
events,
there
must
be
a
strong
reference
from
global
object
specified
by
the
BroadcastChannel
object's
BroadcastChannel
settings
object
to
the
BroadcastChannel
object
itself.
The
close()
method
must
set
the
closed
flag
of
the
BroadcastChannel
object
on
which
it
was
invoked
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
|
message
|
onmessageerror
|
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
// ...
}