How to check if object is Transferable?

21 Views Asked by At

I have written this function to get all transferable elements of an Object — and to get them without duplicates, so the list can actually be used with postMessage().

It includes a check against a pseudo-Abstract Base Class which does lookup against a hard-coded whitelist of known "Transferable" types. This is obviously a nasty, kludgy, fragile hack.

I've written this function because I was unable to find any actual API for doing this check. Does any exist?

function getTransferables(obj, seen=null) {
    seen ||= new WeakSet();

    if (typeof obj !== 'object')
        // Non-transferable leaf
        return [];

    if (seen.has(obj))
        // Avoid infinite loop on cyclic objects
        return [];
    seen.add(obj);
 
    if (obj instanceof _Transferable)
        // Transferable leaf
        return [obj];

    // Recurse
    return Object.entries(obj).flatMap(([,obj]) => getTransferables(obj, seen));
}

// FIXME ugly hack
const _Transferable = Object.assign([
    // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects#supported_objects
    'ArrayBuffer',
    'MessagePort',
    'ReadableStream',
    'WritableStream',
    'TransformStream',
    'WebTransportReceiveStream',
    'WebTransportSendStream',
    'AudioData',
    'ImageBitmap',
    'VideoFrame',
    'OffscreenCanvas',
    'RTCDataChannel'
].map(clsName => {
    "use strict";
    if (!this)
        throw new RuntimeError('could not get global scope');
    return this[clsName];
}).filter(cls => cls), {
    [Symbol.hasInstance](obj) {
        return this.some(cls => obj instanceof cls);
    }
});
<button onclick="{

let a = new ArrayBuffer(69),
    b = new ArrayBuffer(42);

let myObj = ({x: {a, b}, y: {a_again: a}});

let myTransfer = getTransferables(myObj);

console.info(`There are ${myTransfer.length} Transferables in ${JSON.stringify(myObj, (k,v) =&gt; {if (v instanceof _Transferable) return ({[`!${v.__proto__.constructor.name}`]: {}}); return v;})}.`);

}">Demo</button>

0

There are 0 best solutions below