Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose structuredClone #3414

Merged
merged 1 commit into from
Jul 27, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data-x="dom-structuredClone">structuredClone()</code> function.)</p>
data-x="dom-structuredClone">structuredClone()</code> method.)</p>

<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