admin管理员组

文章数量:1399950

I'm working with Web Workers and Buffers recently.

Now I have a buffer and I want to check the sixth byte using SmartBuffer. If that byte is 0, send to worker1. Otherwise, send to worker2.

const buffer = SmartBuffer.fromBuffer(someBuffer);
if(buffer.toBuffer()[5] === 0){
    worker1.postMessage(someBuffer, [someBuffer]);
}
if(buffer.toBuffer()[5] === 1){
    worker2.postMessage(someBuffer, [someBuffer]);
}

Since I use a transferable object, if the someBuffer has been transferred, I cannot access it in line 5 anymore. (It'll cause an error: Cannot perform Construct on a detached ArrayBuffer.)

I know that's a bad example, and I can simply use else if to prevent this error. But the question is: Is there any way to know if a buffer has been transferred?

I'm working with Web Workers and Buffers recently.

Now I have a buffer and I want to check the sixth byte using SmartBuffer. If that byte is 0, send to worker1. Otherwise, send to worker2.

const buffer = SmartBuffer.fromBuffer(someBuffer);
if(buffer.toBuffer()[5] === 0){
    worker1.postMessage(someBuffer, [someBuffer]);
}
if(buffer.toBuffer()[5] === 1){
    worker2.postMessage(someBuffer, [someBuffer]);
}

Since I use a transferable object, if the someBuffer has been transferred, I cannot access it in line 5 anymore. (It'll cause an error: Cannot perform Construct on a detached ArrayBuffer.)

I know that's a bad example, and I can simply use else if to prevent this error. But the question is: Is there any way to know if a buffer has been transferred?

Share Improve this question asked Aug 15, 2018 at 9:21 NoobTWNoobTW 2,5742 gold badges26 silver badges46 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

The byteLength property of a detached ArrayBuffer and each typed array which uses this ArrayBuffer will be zero.

I'm not sure about the internals of the SmartBuffer library but this check should work:

someBuffer.byteLength === 0

This does of course not help if you want to check an ArrayBuffer which has an initial byteLength of zero. In this case nothing will change if it gets detached. But I think this is only a problem in theory.

You can use ArrayBuffer.prototype.detached

const buffer = new ArrayBuffer(8);
console.log(buffer.detached); // false
const newBuffer = buffer.transfer();
console.log(buffer.detached); // true
console.log(newBuffer.detached); // false

Old answer

Currently, the most reliable way to check if it was detached is to use a TypedArray constructor.

While all detached buffers will have byteLength === 0, an empty ArrayBuffer will too and is not considered to be detached.

function isDetached(ab) {
  if(ab.byteLength != 0) {
     // detached buffers will always have zero byteLength
     return false;
  }
  try {
     new Uint8Array(ab);
     return false;
  } catch {
     // Uint8Array throws if using a detached buffer
     return true;
  }
}

const ab = new ArrayBuffer(0);
console.log('isDetached:', isDetached(ab)); // false
structuredClone(ab, { transfer: [ab] }); // detach buffer
console.log('isDetached:', isDetached(ab)); // true

In Node.js it is possible, might be the same (or at least similar) for browsers.

Using util.format(), which is also used in console.log, the detached ArrayBuffer is stringified to something like

ArrayBuffer { (detached), byteLength: 0 }

So checking for detached in the formatted value will tell you exactly that. Example:

function isDetached(buffer: ArrayBuffer): boolean {
  if (buffer.byteLength === 0) {
    const formatted = util.format(buffer)
    return formatted.includes('detached')
  }
  return false
}

本文标签: javascriptHow to check if an ArrayBuffer is detached or transfered in JSStack Overflow