Skip to content

Commit

Permalink
Define self.structuredClone()
Browse files Browse the repository at this point in the history
Closes #793.
  • Loading branch information
surma authored and domenic committed Jul 27, 2021
1 parent 0d63ebc commit 1e610d4
Showing 1 changed file with 70 additions and 23 deletions.
93 changes: 70 additions & 23 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -7967,13 +7967,24 @@ interface <dfn interface>DOMStringList</dfn> {
</div>


<div w-nodev>

<h3 split-filename="structured-data">Safe passing of structured data</h3>

<p id="structuredclone"><span id="structured-clone"></span>To support passing JavaScript objects,
including <span data-x="platform object">platform objects</span>, across <span data-x="JavaScript
realm">realm</span> boundaries, this specification defines <span w-nodev>the following
</span>infrastructure for serializing and deserializing objects, including in some cases
transferring the underlying data instead of copying it. Collectively this
serialization/deserialization process is known as "structured cloning", although most APIs perform
separate serialization and deserialization steps. (With the notable exception being the <code
data-x="dom-structuredClone">structuredClone()</code> method.)</p>

<div w-nodev>

<p>This section uses the terminology and typographic conventions from the JavaScript
specification. <ref spec=JAVASCRIPT></p>

</div>

<h4><dfn>Serializable objects</dfn></h4>

<p><span>Serializable objects</span> support being serialized, and later deserialized, in a way
Expand All @@ -7984,6 +7995,8 @@ interface <dfn interface>DOMStringList</dfn> {
<p>Not all objects are <span>serializable objects</span>, and not all aspects of objects that are
<span>serializable objects</span> are necessarily preserved when they are serialized.</p>

<div w-nodev>

<p><span data-x="platform object">Platform objects</span> can be <span>serializable objects</span>
if their <span>primary interface</span> is decorated with the <dfn extended-attribute
data-lt="Serializable" data-x="Serializable"><code>[Serializable]</code></dfn> IDL <span>extended
Expand Down Expand Up @@ -8091,6 +8104,8 @@ interface <dfn interface>DOMStringList</dfn> {
However, to better specify the behavior of certain more complex situations, the model was updated
to make the serialization and deserialization explicit.</p>

</div>

<h4 export data-lt="transferable object"><dfn>Transferable objects</dfn></h4>

<p><span>Transferable objects</span> support being transferred across <span
Expand All @@ -8103,6 +8118,8 @@ interface <dfn interface>DOMStringList</dfn> {
<p class="note">Transferring is an irreversible and non-idempotent operation. Once an object has
been transferred, it cannot be transferred, or indeed used, again.</p>

<div w-nodev>

<p><span data-x="platform object">Platform objects</span> can be <span>transferable objects</span>
if their <span>primary interface</span> is decorated with the <dfn extended-attribute
data-lt="Transferable" data-x="Transferable"><code>[Transferable]</code></dfn> IDL <span>extended
Expand Down Expand Up @@ -9138,11 +9155,6 @@ o.myself = o;</code></pre>
understood to perform an implicit <span data-x="concept-idl-convert">conversion</span> to the
JavaScript value before invoking these algorithms.</p>

<p class="note" id="structuredclone"><span id="structured-clone"></span>This specification used
to define a "structured clone" algorithm, and more recently a StructuredClone abstract operation.
However, in practice all known uses of it were better served by separate serialization and
deserialization steps, so it was removed.</p>

<hr>

<p>Call sites that are not invoked as a result of author code synchronously calling into a user
Expand Down Expand Up @@ -9170,6 +9182,39 @@ o.myself = o;</code></pre>

</div>

<h4 id="structured-cloning">Structured cloning API</h4>

<dl class="domintro">
<dt><var>result</var> = self . <code subdfn data-x="dom-structuredClone">structuredClone</code>( <var>value</var>
[, { <code data-x="dom-StructuredSerializeOptions-transfer">transfer</code> } ] )</dt>
<dd>
<p>Takes the input value and returns a deep copy by performing the structured clone algorithm.
<span>Transferable objects</span> listed in the <code
data-x="dom-StructuredSerializeOptions-transfer">transfer</code> array are transferred, not
just cloned, meaning that they are no longer usable in the input value.</p>

<p>Throws a <span>"<code>DataCloneError</code>"</span> <code>DOMException</code> if any part of
the input value is not <span data-x="serializable objects">serializable</span>.</p>
</dd>
</dl>

<div w-nodev>

<p>The <dfn method for="WindowOrWorkerGlobalScope"
data-x="dom-structuredClone"><code>structuredClone(<var>value</var>,
<var>options</var>)</code></dfn> method steps are:</p>

<ol>
<li><p>Let <var>serialized</var> be ?
<span>StructuredSerializeWithTransfer</span>(<var>value</var>, <var>options</var>["<code
data-x="dom-StructuredSerializeOptions-transfer">transfer</code>"]).</p></li>

<li><p>Return ? <span>StructuredDeserialize</span>(<var>serialized</var>, <span>this</span>'s
<span data-x="concept-relevant-realm">relevant Realm</span>).</p></li>
</ol>

</div>


<h2 split-filename="dom" id="dom">Semantics, structure, and APIs of HTML documents</h2>

Expand Down Expand Up @@ -80416,7 +80461,7 @@ interface <dfn interface>Window</dfn> : <span>EventTarget</span> {
<span>Window</span> includes <span>GlobalEventHandlers</span>;
<span>Window</span> includes <span>WindowEventHandlers</span>;

dictionary <dfn dictionary>WindowPostMessageOptions</dfn> : <span>PostMessageOptions</span> {
dictionary <dfn dictionary>WindowPostMessageOptions</dfn> : <span>StructuredSerializeOptions</span> {
USVString <dfn dict-member for="WindowPostMessageOptions" data-x="dom-WindowPostMessageOptions-targetOrigin">targetOrigin</dfn> = "/";
};</code></pre>

Expand Down Expand Up @@ -94809,6 +94854,9 @@ interface mixin <dfn interface>WindowOrWorkerGlobalScope</dfn> {
// ImageBitmap
Promise&lt;<span>ImageBitmap</span>&gt; <span data-x="dom-createImageBitmap">createImageBitmap</span>(<span>ImageBitmapSource</span> image, optional <span>ImageBitmapOptions</span> options = {});
Promise&lt;<span>ImageBitmap</span>&gt; <span data-x="dom-createImageBitmap">createImageBitmap</span>(<span>ImageBitmapSource</span> image, long sx, long sy, long sw, long sh, optional <span>ImageBitmapOptions</span> options = {});

// structured cloning
any <span data-x="dom-structuredClone">structuredClone</span>(any value, optional <span>StructuredSerializeOptions</span> options = {});
};
<span>Window</span> includes <span>WindowOrWorkerGlobalScope</span>;
<span>WorkerGlobalScope</span> includes <span>WindowOrWorkerGlobalScope</span>;</code></pre>
Expand Down Expand Up @@ -99740,7 +99788,7 @@ function receiver(e) {
and can contain certain data objects such as <code>File</code> <code>Blob</code>,
<code>FileList</code>, and <code data-x="idl-ArrayBuffer">ArrayBuffer</code> objects.</p>

<p>Objects listed in the <code data-x="dom-PostMessageOptions-transfer">transfer</code> member
<p>Objects listed in the <code data-x="dom-StructuredSerializeOptions-transfer">transfer</code> member
of <var>options</var> are transferred, not just cloned, meaning that they are no longer usable
on the sending side.</p>

Expand Down Expand Up @@ -99816,7 +99864,7 @@ function receiver(e) {
</li>

<li><p>Let <var>transfer</var> be <var>options</var>["<code
data-x="dom-PostMessageOptions-transfer">transfer</code>"].</p></li>
data-x="dom-StructuredSerializeOptions-transfer">transfer</code>"].</p></li>

<li><p>Let <var>serializeWithTransferResult</var> be
<span>StructuredSerializeWithTransfer</span>(<var>message</var>, <var>transfer</var>). Rethrow
Expand Down Expand Up @@ -99892,7 +99940,7 @@ function receiver(e) {

<li><p>Let <var>options</var> be «[ "<code
data-x="dom-WindowPostMessageOptions-targetOrigin">targetOrigin</code>" →
<var>targetOrigin</var>, "<code data-x="dom-PostMessageOptions-transfer">transfer</code>" →
<var>targetOrigin</var>, "<code data-x="dom-StructuredSerializeOptions-transfer">transfer</code>" →
<var>transfer</var> ]».</p></li>

<li><p>Run the <span>window post message steps</span> providing <var>targetWindow</var>,
Expand Down Expand Up @@ -100160,7 +100208,7 @@ interface <dfn interface>MessageChannel</dfn> {
<pre><code class="idl">[Exposed=(Window,Worker,AudioWorklet), <span>Transferable</span>]
interface <dfn interface>MessagePort</dfn> : <span>EventTarget</span> {
undefined <span data-x="dom-MessagePort-postMessage">postMessage</span>(any message, sequence&lt;<span data-x="idl-object">object</span>&gt; transfer);
undefined <span data-x="dom-MessagePort-postMessage-options">postMessage</span>(any message, optional <span>PostMessageOptions</span> options = {});
undefined <span data-x="dom-MessagePort-postMessage-options">postMessage</span>(any message, optional <span>StructuredSerializeOptions</span> options = {});
undefined <span data-x="dom-MessagePort-start">start</span>();
undefined <span data-x="dom-MessagePort-close">close</span>();

Expand All @@ -100169,8 +100217,8 @@ interface <dfn interface>MessagePort</dfn> : <span>EventTarget</span> {
attribute <span>EventHandler</span> <span data-x="handler-MessagePort-onmessageerror">onmessageerror</span>;
};

dictionary <dfn dictionary>PostMessageOptions</dfn> {
sequence&lt;<span data-x="idl-object">object</span>&gt; <dfn dict-member for="PostMessageOptions" data-x="dom-PostMessageOptions-transfer">transfer</dfn> = [];
dictionary <dfn dictionary>StructuredSerializeOptions</dfn> {
sequence&lt;<span data-x="idl-object">object</span>&gt; <dfn dict-member for="StructuredSerializeOptions" data-x="dom-StructuredSerializeOptions-transfer">transfer</dfn> = [];
};</code></pre>

<dl class="domintro">
Expand Down Expand Up @@ -100313,7 +100361,7 @@ dictionary <dfn dictionary>PostMessageOptions</dfn> {

<ol> <!-- a lot of this is similar or identical to the window post message steps -->
<li><p>Let <var>transfer</var> be <var>options</var>["<code
data-x="dom-PostMessageOptions-transfer">transfer</code>"].</p></li>
data-x="dom-StructuredSerializeOptions-transfer">transfer</code>"].</p></li>

<li><p>If <var>transfer</var> <span data-x="list contains">contains</span> this
<code>MessagePort</code>, then throw a <span>"<code>DataCloneError</code>"</span>
Expand Down Expand Up @@ -100403,7 +100451,8 @@ dictionary <dfn dictionary>PostMessageOptions</dfn> {
entangled, if any; otherwise let it be null.</p></li>

<li><p>Let <var>options</var> be «[ "<code
data-x="dom-PostMessageOptions-transfer">transfer</code>" → <var>transfer</var> ]».</p></li>
data-x="dom-StructuredSerializeOptions-transfer">transfer</code>" →
<var>transfer</var> ]».</p></li>

<li><p>Run the <span>message port post message steps</span> providing <var>targetPort</var>,
<var>message</var> and <var>options</var>.</p></li>
Expand Down Expand Up @@ -101272,7 +101321,7 @@ interface <dfn interface>DedicatedWorkerGlobalScope</dfn> : <span>WorkerGlobalSc
[Replaceable] readonly attribute DOMString <span data-x="dom-DedicatedWorkerGlobalScope-name">name</span>;

undefined <span data-x="dom-DedicatedWorkerGlobalScope-postMessage">postMessage</span>(any message, sequence&lt;<span data-x="idl-object">object</span>&gt; transfer);
undefined <span data-x="dom-DedicatedWorkerGlobalScope-postMessage-options">postMessage</span>(any message, optional <span>PostMessageOptions</span> options = {});
undefined <span data-x="dom-DedicatedWorkerGlobalScope-postMessage-options">postMessage</span>(any message, optional <span>StructuredSerializeOptions</span> options = {});

undefined <span data-x="dom-DedicatedWorkerGlobalScope-close">close</span>();

Expand All @@ -101294,10 +101343,8 @@ interface <dfn interface>DedicatedWorkerGlobalScope</dfn> : <span>WorkerGlobalSc
data-x="concept-WorkerGlobalScope-name">name</span>, i.e. the value given to the
<code>Worker</code> constructor. Primarily useful for debugging.</p></dd>

<dt><code data-x=""><var>dedicatedWorkerGlobal</var>.<span subdfn data-x="dom-DedicatedWorkerGlobalScope-postMessage">postMessage</span>(<var>message</var> [,
<var>transfer</var> ])</code></dt>
<dt><code data-x=""><var>dedicatedWorkerGlobal</var>.<span subdfn data-x="dom-DedicatedWorkerGlobalScope-postMessage-options">postMessage</span>(<var>message</var>
[, { <span data-x="dom-PostMessageOptions-transfer">transfer</span> } ])</code></dt>
<dt><code data-x=""><var>dedicatedWorkerGlobal</var>.<span subdfn data-x="dom-DedicatedWorkerGlobalScope-postMessage">postMessage</span>(<var>message</var> [, <var>transfer</var> ])</code></dt>
<dt><code data-x=""><var>dedicatedWorkerGlobal</var>.<span subdfn data-x="dom-DedicatedWorkerGlobalScope-postMessage-options">postMessage</span>(<var>message</var> [, { <span data-x="dom-StructuredSerializeOptions-transfer">transfer</span> } ])</code></dt>
<dd><p>Clones <var>message</var> and transmits it to the <code>Worker</code> object associated
with <var>dedicatedWorkerGlobal</var>. <var>transfer</var> can be passed as a list of objects
that are to be transferred rather than cloned.</p></dd>
Expand Down Expand Up @@ -102007,7 +102054,7 @@ interface <dfn interface>Worker</dfn> : <span>EventTarget</span> {
undefined <span data-x="dom-Worker-terminate">terminate</span>();

undefined <span data-x="dom-Worker-postMessage">postMessage</span>(any message, sequence&lt;<span data-x="idl-object">object</span>&gt; transfer);
undefined <span data-x="dom-Worker-postMessage-options">postMessage</span>(any message, optional <span>PostMessageOptions</span> options = {});
undefined <span data-x="dom-Worker-postMessage-options">postMessage</span>(any message, optional <span>StructuredSerializeOptions</span> options = {});
attribute <span>EventHandler</span> <span data-x="handler-Worker-onmessage">onmessage</span>;
attribute <span>EventHandler</span> <span data-x="handler-Worker-onmessageerror">onmessageerror</span>;
};
Expand Down Expand Up @@ -102037,7 +102084,7 @@ enum <dfn enum>WorkerType</dfn> { "classic", "module" };
<dd>Aborts <var>worker</var>'s associated global environment.</dd>

<dt><code data-x=""><var>worker</var>.<span subdfn data-x="dom-Worker-postMessage">postMessage</span>(<var>message</var> [, <var>transfer</var> ])</code></dt>
<dt><code data-x=""><var>worker</var>.<span subdfn data-x="dom-Worker-postMessage-options">postMessage</span>(<var>message</var> [, { <span data-x="dom-PostMessageOptions-transfer">transfer</span> } ])</code></dt>
<dt><code data-x=""><var>worker</var>.<span subdfn data-x="dom-Worker-postMessage-options">postMessage</span>(<var>message</var> [, { <span data-x="dom-StructuredSerializeOptions-transfer">transfer</span> } ])</code></dt>
<dd><p>Clones <var>message</var> and transmits it to <var>worker</var>'s global environment.
<var>transfer</var> can be passed as a list of objects that are to be transferred rather than
cloned.</p></dd>
Expand Down

0 comments on commit 1e610d4

Please sign in to comment.