| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b36f8c2 commit 5fda4a1
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -194,6 +194,38 @@ isMarkedAsUntransferable(pooledBuffer); // Returns true. | |||
| 194 | 194 | ||
| 195 | 195 | There is no equivalent to this API in browsers. | |
| 196 | 196 | ||
| 197 | + ## `worker.markAsUncloneable(object)` | ||
| 198 | + | ||
| 199 | + <!-- YAML | ||
| 200 | + added: REPLACEME | ||
| 201 | + --> | ||
| 202 | + | ||
| 203 | + * `object` {any} Any arbitrary JavaScript value. | ||
| 204 | + | ||
| 205 | + Mark an object as not cloneable. If `object` is used as [`message`](#event-message) in | ||
| 206 | + a [`port.postMessage()`][] call, an error is thrown. This is a no-op if `object` is a | ||
| 207 | + primitive value. | ||
| 208 | + | ||
| 209 | + This has no effect on `ArrayBuffer`, or any `Buffer` like objects. | ||
| 210 | + | ||
| 211 | + This operation cannot be undone. | ||
| 212 | + | ||
| 213 | + ```js | ||
| 214 | + const { markAsUncloneable } = require('node:worker_threads'); | ||
| 215 | + | ||
| 216 | + const anyObject = { foo: 'bar' }; | ||
| 217 | + markAsUncloneable(anyObject); | ||
| 218 | + const { port1 } = new MessageChannel(); | ||
| 219 | + try { | ||
| 220 | + // This will throw an error, because anyObject is not cloneable. | ||
| 221 | + port1.postMessage(anyObject) | ||
| 222 | + } catch (error) { | ||
| 223 | + // error.name === 'DataCloneError' | ||
| 224 | + } | ||
| 225 | + ``` | ||
| 226 | + | ||
| 227 | + There is no equivalent to this API in browsers. | ||
| 228 | + | ||
| 197 | 229 | ## `worker.moveMessagePortToContext(port, contextifiedSandbox)` | |
| 198 | 230 | ||
| 199 | 231 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,6 +29,14 @@ const { | |||
| 29 | 29 | oninit: onInitSymbol, | |
| 30 | 30 | no_message_symbol: noMessageSymbol, | |
| 31 | 31 | } = internalBinding('symbols'); | |
| 32 | + const { | ||
| 33 | + privateSymbols: { | ||
| 34 | + transfer_mode_private_symbol, | ||
| 35 | + }, | ||
| 36 | + constants: { | ||
| 37 | + kCloneable, | ||
| 38 | + }, | ||
| 39 | + } = internalBinding('util'); | ||
| 32 | 40 | const { | |
| 33 | 41 | MessagePort, | |
| 34 | 42 | MessageChannel, | |
@@ -447,13 +455,21 @@ ObjectDefineProperties(BroadcastChannel.prototype, { | |||
| 447 | 455 | defineEventHandler(BroadcastChannel.prototype, 'message'); | |
| 448 | 456 | defineEventHandler(BroadcastChannel.prototype, 'messageerror'); | |
| 449 | 457 | ||
| 458 | + function markAsUncloneable(obj) { | ||
| 459 | + if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null) { | ||
| 460 | + return; | ||
| 461 | + } | ||
| 462 | + obj[transfer_mode_private_symbol] &= ~kCloneable; | ||
| 463 | + } | ||
| 464 | + | ||
| 450 | 465 | module.exports = { | |
| 451 | 466 | drainMessagePort, | |
| 452 | 467 | messageTypes, | |
| 453 | 468 | kPort, | |
| 454 | 469 | kIncrementsPortRef, | |
| 455 | 470 | kWaitingStreams, | |
| 456 | 471 | kStdioWantsMoreDataCallback, | |
| 472 | + markAsUncloneable, | ||
| 457 | 473 | moveMessagePortToContext, | |
| 458 | 474 | MessagePort, | |
| 459 | 475 | MessageChannel, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,7 @@ const { | |||
| 13 | 13 | const { | |
| 14 | 14 | MessagePort, | |
| 15 | 15 | MessageChannel, | |
| 16 | + markAsUncloneable, | ||
| 16 | 17 | moveMessagePortToContext, | |
| 17 | 18 | receiveMessageOnPort, | |
| 18 | 19 | BroadcastChannel, | |
@@ -31,6 +32,7 @@ module.exports = { | |||
| 31 | 32 | isMainThread, | |
| 32 | 33 | MessagePort, | |
| 33 | 34 | MessageChannel, | |
| 35 | + markAsUncloneable, | ||
| 34 | 36 | markAsUntransferable, | |
| 35 | 37 | isMarkedAsUntransferable, | |
| 36 | 38 | moveMessagePortToContext, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,70 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { markAsUncloneable } = require('node:worker_threads'); | ||
| 6 | + const { mustCall } = require('../common'); | ||
| 7 | + | ||
| 8 | + const expectedErrorName = 'DataCloneError'; | ||
| 9 | + | ||
| 10 | + // Uncloneables cannot be cloned during message posting | ||
| 11 | + { | ||
| 12 | + const anyObject = { foo: 'bar' }; | ||
| 13 | + markAsUncloneable(anyObject); | ||
| 14 | + const { port1 } = new MessageChannel(); | ||
| 15 | + assert.throws(() => port1.postMessage(anyObject), { | ||
| 16 | + constructor: DOMException, | ||
| 17 | + name: expectedErrorName, | ||
| 18 | + code: 25, | ||
| 19 | + }, `Should throw ${expectedErrorName} when posting uncloneables`); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + // Uncloneables cannot be cloned during structured cloning | ||
| 23 | + { | ||
| 24 | + class MockResponse extends Response { | ||
| 25 | + constructor() { | ||
| 26 | + super(); | ||
| 27 | + markAsUncloneable(this); | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + structuredClone(MockResponse.prototype); | ||
| 31 | + | ||
| 32 | + markAsUncloneable(MockResponse.prototype); | ||
| 33 | + const r = new MockResponse(); | ||
| 34 | + assert.throws(() => structuredClone(r), { | ||
| 35 | + constructor: DOMException, | ||
| 36 | + name: expectedErrorName, | ||
| 37 | + code: 25, | ||
| 38 | + }, `Should throw ${expectedErrorName} when cloning uncloneables`); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // markAsUncloneable cannot affect ArrayBuffer | ||
| 42 | + { | ||
| 43 | + const pooledBuffer = new ArrayBuffer(8); | ||
| 44 | + const { port1, port2 } = new MessageChannel(); | ||
| 45 | + markAsUncloneable(pooledBuffer); | ||
| 46 | + port1.postMessage(pooledBuffer); | ||
| 47 | + port2.on('message', mustCall((value) => { | ||
| 48 | + assert.deepStrictEqual(value, pooledBuffer); | ||
| 49 | + port2.close(mustCall()); | ||
| 50 | + })); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + // markAsUncloneable can affect Node.js built-in object like Blob | ||
| 54 | + { | ||
| 55 | + const cloneableBlob = new Blob(); | ||
| 56 | + const { port1, port2 } = new MessageChannel(); | ||
| 57 | + port1.postMessage(cloneableBlob); | ||
| 58 | + port2.on('message', mustCall((value) => { | ||
| 59 | + assert.deepStrictEqual(value, cloneableBlob); | ||
| 60 | + port2.close(mustCall()); | ||
| 61 | + })); | ||
| 62 | + | ||
| 63 | + const uncloneableBlob = new Blob(); | ||
| 64 | + markAsUncloneable(uncloneableBlob); | ||
| 65 | + assert.throws(() => port1.postMessage(uncloneableBlob), { | ||
| 66 | + constructor: DOMException, | ||
| 67 | + name: expectedErrorName, | ||
| 68 | + code: 25, | ||
| 69 | + }, `Should throw ${expectedErrorName} when cloning uncloneables`); | ||
| 70 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments