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

[v14.x backport] buffer: introduce Blob #39704

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
114 changes: 114 additions & 0 deletions doc/api/buffer.md
Expand Up @@ -279,6 +279,119 @@ for (const b of buf) {
Additionally, the [`buf.values()`][], [`buf.keys()`][], and
[`buf.entries()`][] methods can be used to create iterators.

## Class: `Blob`
<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental

A [`Blob`][] encapsulates immutable, raw data that can be safely shared across
multiple worker threads.

### `new buffer.Blob([sources[, options]])`
<!-- YAML
added: REPLACEME
-->

* `sources` {string[]|ArrayBuffer[]|TypedArray[]|DataView[]|Blob[]} An array
of string, {ArrayBuffer}, {TypedArray}, {DataView}, or {Blob} objects, or
any mix of such objects, that will be stored within the `Blob`.
* `options` {Object}
* `encoding` {string} The character encoding to use for string sources.
**Default**: `'utf8'`.
* `type` {string} The Blob content-type. The intent is for `type` to convey
the MIME media type of the data, however no validation of the type format
is performed.

Creates a new `Blob` object containing a concatenation of the given sources.

{ArrayBuffer}, {TypedArray}, {DataView}, and {Buffer} sources are copied into
the 'Blob' and can therefore be safely modified after the 'Blob' is created.

String sources are also copied into the `Blob`.

### `blob.arrayBuffer()`
<!-- YAML
added: REPLACEME
-->

* Returns: {Promise}

Returns a promise that fulfills with an {ArrayBuffer} containing a copy of
the `Blob` data.

### `blob.size`
<!-- YAML
added: REPLACEME
-->

The total size of the `Blob` in bytes.

### `blob.slice([start, [end, [type]]])`
<!-- YAML
added: REPLACEME
-->

* `start` {number} The starting index.
* `end` {number} The ending index.
* `type` {string} The content-type for the new `Blob`

Creates and returns a new `Blob` containing a subset of this `Blob` objects
data. The original `Blob` is not alterered.

### `blob.text()`
<!-- YAML
added: REPLACEME
-->

* Returns: {Promise}

Returns a promise that resolves the contents of the `Blob` decoded as a UTF-8
string.

### `blob.type`
<!-- YAML
added: REPLACEME
-->

* Type: {string}

The content-type of the `Blob`.

### `Blob` objects and `MessageChannel`

Once a {Blob} object is created, it can be sent via `MessagePort` to multiple
destinations without transfering or immediately copying the data. The data
contained by the `Blob` is copied only when the `arrayBuffer()` or `text()`
methods are called.

```js
const { Blob } = require('buffer');
const blob = new Blob(['hello there']);
const { setTimeout: delay } = require('timers/promises');

const mc1 = new MessageChannel();
const mc2 = new MessageChannel();

mc1.port1.onmessage = async ({ data }) => {
console.log(await data.arrayBuffer());
mc1.port1.close();
};

mc2.port1.onmessage = async ({ data }) => {
await delay(1000);
console.log(await data.arrayBuffer());
mc2.port1.close();
};

mc1.port2.postMessage(blob);
mc2.port2.postMessage(blob);

// The Blob is still usable after posting.
data.text().then(console.log);
```

## Class: `Buffer`

The `Buffer` class is a global type for dealing with binary data directly.
Expand Down Expand Up @@ -3388,6 +3501,7 @@ introducing security vulnerabilities into an application.
[UTF-8]: https://en.wikipedia.org/wiki/UTF-8
[WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/
[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
[`Blob`]: https://developer.mozilla.org/en-US/docs/Web/API/Blob
[`Buffer.alloc()`]: #buffer_static_method_buffer_alloc_size_fill_encoding
[`Buffer.allocUnsafe()`]: #buffer_static_method_buffer_allocunsafe_size
[`Buffer.allocUnsafeSlow()`]: #buffer_static_method_buffer_allocunsafeslow_size
Expand Down
5 changes: 5 additions & 0 deletions lib/buffer.js
Expand Up @@ -116,6 +116,10 @@ const {
addBufferPrototypeMethods
} = require('internal/buffer');

const {
Blob,
} = require('internal/blob');

FastBuffer.prototype.constructor = Buffer;
Buffer.prototype = FastBuffer.prototype;
addBufferPrototypeMethods(Buffer.prototype);
Expand Down Expand Up @@ -1240,6 +1244,7 @@ function atob(input) {
}

module.exports = {
Blob,
Buffer,
SlowBuffer,
transcode,
Expand Down
9 changes: 2 additions & 7 deletions lib/child_process.js
Expand Up @@ -28,12 +28,12 @@ const {
ObjectAssign,
ObjectDefineProperty,
ObjectPrototypeHasOwnProperty,
Promise,
} = primordials;

const {
promisify,
convertToValidSignal,
createDeferredPromise,
getSystemErrorName
} = require('internal/util');
const { isArrayBufferView } = require('internal/util/types');
Expand Down Expand Up @@ -215,12 +215,7 @@ function exec(command, options, callback) {

const customPromiseExecFunction = (orig) => {
return (...args) => {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
const { promise, resolve, reject } = createDeferredPromise();

promise.child = orig(...args, (err, stdout, stderr) => {
if (err !== null) {
Expand Down