refactor: use v8 serialization for ipc (#20214)

* refactor: use v8 serialization for ipc

* cloning process.env doesn't work

* serialize host objects by enumerating key/values

* new serialization can handle NaN, Infinity, and undefined correctly

* can't allocate v8 objects during GC

* backport microtasks fix

* fix compile

* fix node_stream_loader reentrancy

* update subframe spec to expect undefined instead of null

* write undefined instead of crashing when serializing host objects

* fix webview spec

* fix download spec

* buffers are transformed into uint8arrays

* can't serialize promises

* fix chrome.i18n.getMessage

* fix devtools tests

* fix zoom test

* fix debug build

* fix lint

* update ipcRenderer tests

* fix printToPDF test

* update patch

* remove accidentally re-added remote-side spec

* wip

* don't attempt to serialize host objects

* jump through different hoops to set options.webContents sometimes

* whoops

* fix lint

* clean up error-handling logic

* fix memory leak

* fix lint

* convert host objects using old base::Value serialization

* fix lint more

* fall back to base::Value-based serialization

* remove commented-out code

* add docs to breaking-changes.md

* Update breaking-changes.md

* update ipcRenderer and WebContents docs

* lint

* use named values for format tag

* save a memcpy for ~30% speedup

* get rid of calls to ShallowClone

* extra debugging for paranoia

* d'oh, use the correct named tags

* apparently msstl doesn't like this DCHECK

* funny story about that DCHECK

* disable remote-related functions when enable_remote_module = false

* nits

* use EnableIf to disable remote methods in mojom

* fix include

* review comments
This commit is contained in:
Jeremy Apthorp 2019-10-09 10:59:08 -07:00 committed by John Kleinschmidt
parent c250cd6e7c
commit 2fad53e66b
38 changed files with 623 additions and 169 deletions

View file

@ -6,6 +6,59 @@ Breaking changes will be documented here, and deprecation warnings added to JS c
The `FIXME` string is used in code comments to denote things that should be fixed for future releases. See https://github.com/electron/electron/search?q=fixme
## Planned Breaking API Changes (8.0)
### Values sent over IPC are now serialized with Structured Clone Algorithm
The algorithm used to serialize objects sent over IPC (through
`ipcRenderer.send`, `ipcRenderer.sendSync`, `WebContents.send` and related
methods) has been switched from a custom algorithm to V8's built-in [Structured
Clone Algorithm][SCA], the same algorithm used to serialize messages for
`postMessage`. This brings about a 2x performance improvement for large
messages, but also brings some breaking changes in behavior.
- Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any
such values, over IPC will now throw an exception, instead of silently
converting the functions to `undefined`.
```js
// Previously:
ipcRenderer.send('channel', { value: 3, someFunction: () => {} })
// => results in { value: 3 } arriving in the main process
// From Electron 8:
ipcRenderer.send('channel', { value: 3, someFunction: () => {} })
// => throws Error("() => {} could not be cloned.")
```
- `NaN`, `Infinity` and `-Infinity` will now be correctly serialized, instead
of being converted to `null`.
- Objects containing cyclic references will now be correctly serialized,
instead of being converted to `null`.
- `Set`, `Map`, `Error` and `RegExp` values will be correctly serialized,
instead of being converted to `{}`.
- `BigInt` values will be correctly serialized, instead of being converted to
`null`.
- Sparse arrays will be serialized as such, instead of being converted to dense
arrays with `null`s.
- `Date` objects will be transferred as `Date` objects, instead of being
converted to their ISO string representation.
- Typed Arrays (such as `Uint8Array`, `Uint16Array`, `Uint32Array` and so on)
will be transferred as such, instead of being converted to Node.js `Buffer`.
- Node.js `Buffer` objects will be transferred as `Uint8Array`s. You can
convert a `Uint8Array` back to a Node.js `Buffer` by wrapping the underlying
`ArrayBuffer`:
```js
Buffer.from(value.buffer, value.byteOffset, value.byteLength)
```
Sending any objects that aren't native JS types, such as DOM objects (e.g.
`Element`, `Location`, `DOMMatrix`), Node.js objects (e.g. `process.env`,
`Stream`), or Electron objects (e.g. `WebContents`, `BrowserWindow`,
`WebFrame`) is deprecated. In Electron 8, these objects will be serialized as
before with a DeprecationWarning message, but starting in Electron 9, sending
these kinds of objects will throw a 'could not be cloned' error.
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
## Planned Breaking API Changes (7.0)
### Node Headers URL

View file

@ -55,9 +55,15 @@ Removes all listeners, or those of the specified `channel`.
* `channel` String
* `...args` any[]
Send a message to the main process asynchronously via `channel`, you can also
send arbitrary arguments. Arguments will be serialized as JSON internally and
hence no functions or prototype chain will be included.
Send an asynchronous message to the main process via `channel`, along with
arguments. Arguments will be serialized with the [Structured Clone
Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
throw an exception.
> **NOTE**: Sending non-standard JavaScript types such as DOM objects or
> special Electron objects is deprecated, and will begin throwing an exception
> starting with Electron 9.
The main process handles it by listening for `channel` with the
[`ipcMain`](ipc-main.md) module.
@ -69,9 +75,15 @@ The main process handles it by listening for `channel` with the
Returns `Promise<any>` - Resolves with the response from the main process.
Send a message to the main process asynchronously via `channel` and expect an
asynchronous result. Arguments will be serialized as JSON internally and
hence no functions or prototype chain will be included.
Send a message to the main process via `channel` and expect a result
asynchronously. Arguments will be serialized with the [Structured Clone
Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
throw an exception.
> **NOTE**: Sending non-standard JavaScript types such as DOM objects or
> special Electron objects is deprecated, and will begin throwing an exception
> starting with Electron 9.
The main process should listen for `channel` with
[`ipcMain.handle()`](ipc-main.md#ipcmainhandlechannel-listener).
@ -97,15 +109,23 @@ ipcMain.handle('some-name', async (event, someArgument) => {
Returns `any` - The value sent back by the [`ipcMain`](ipc-main.md) handler.
Send a message to the main process synchronously via `channel`, you can also
send arbitrary arguments. Arguments will be serialized in JSON internally and
hence no functions or prototype chain will be included.
Send a message to the main process via `channel` and expect a result
synchronously. Arguments will be serialized with the [Structured Clone
Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
throw an exception.
> **NOTE**: Sending non-standard JavaScript types such as DOM objects or
> special Electron objects is deprecated, and will begin throwing an exception
> starting with Electron 9.
The main process handles it by listening for `channel` with [`ipcMain`](ipc-main.md) module,
and replies by setting `event.returnValue`.
**Note:** Sending a synchronous message will block the whole renderer process,
unless you know what you are doing you should never use it.
> :warning: **WARNING**: Sending a synchronous message will block the whole
> renderer process until the reply is received, so use this method only as a
> last resort. It's much better to use the asynchronous version,
> [`invoke()`](ipc-renderer.md#ipcrendererinvokechannel-args).
### `ipcRenderer.sendTo(webContentsId, channel, ...args)`
@ -129,3 +149,5 @@ The documentation for the `event` object passed to the `callback` can be found
in the [`ipc-renderer-event`](structures/ipc-renderer-event.md) structure docs.
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

View file

@ -1479,9 +1479,15 @@ Opens the developer tools for the service worker context.
* `channel` String
* `...args` any[]
Send an asynchronous message to renderer process via `channel`, you can also
send arbitrary arguments. Arguments will be serialized in JSON internally and
hence no functions or prototype chain will be included.
Send an asynchronous message to the renderer process via `channel`, along with
arguments. Arguments will be serialized with the [Structured Clone
Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
throw an exception.
> **NOTE**: Sending non-standard JavaScript types such as DOM objects or
> special Electron objects is deprecated, and will begin throwing an exception
> starting with Electron 9.
The renderer process can handle the message by listening to `channel` with the
[`ipcRenderer`](ipc-renderer.md) module.
@ -1522,8 +1528,14 @@ app.on('ready', () => {
* `...args` any[]
Send an asynchronous message to a specific frame in a renderer process via
`channel`. Arguments will be serialized
as JSON internally and as such no functions or prototype chains will be included.
`channel`, along with arguments. Arguments will be serialized with the
[Structured Clone Algorithm][SCA], just like [`postMessage`][], so prototype
chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or
WeakSets will throw an exception.
> **NOTE**: Sending non-standard JavaScript types such as DOM objects or
> special Electron objects is deprecated, and will begin throwing an exception
> starting with Electron 9.
The renderer process can handle the message by listening to `channel` with the
[`ipcRenderer`](ipc-renderer.md) module.
@ -1785,3 +1797,5 @@ A [`Debugger`](debugger.md) instance for this webContents.
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage