0

Why is readAsBinaryString() deprecated? From W3C

The use of readAsArrayBuffer() is preferred over readAsBinaryString(), which is provided for backwards compatibility.

readAsBinaryString returns a completely different thing than the other method, so how could one be the replacement for the other?

In my specific case I have a Blob that I need to convert to base64, there are many ways, but most of them not memory efficient. As of my tests calling window.btoa() from readAsBinaryString' result works best. If I cannot use this anymore (or for now lets say "should"), then I must convert the array to a string using iteration and strings concatenation which is not memory efficient at all!

So after researching for days I don't really find an alternative to readAsBinaryString, that's why the question, or do you see an alternative that also works with 100MB blobs?

David
  • 3,971
  • 1
  • 26
  • 65
  • 6
    You're misunderstanding the difference between deprecated and preferred use – Sterling Archer Apr 24 '19 at 18:54
  • But they say they removed the function first and then added it again only for backward compatibility, so this means they will remove it one day. – David Apr 24 '19 at 18:55
  • "While a deprecated software feature remains in the software, its use may raise warning messages recommending alternative practices; deprecated status may also indicate the feature will be removed in the future. Features are deprecated rather than immediately removed, to provide backward compatibility, and to give programmers time to bring affected code into compliance with the new standard." -- Wikipedia –  Apr 24 '19 at 18:57
  • Lots of methods will be deprecated one day, you simply adapt when it happens :) As of right now, unless you want to adjust your code to use `ArrayBuffer`, it seems like a null issue – Sterling Archer Apr 24 '19 at 18:57
  • A little research reveals http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/1543.html –  Apr 24 '19 at 18:57
  • It's a bit of a pita but you can move forwards and backwards in that thread to glean some of the reasoning, such as *This method predates support for typed arrays in the FileAPI and allows binary data to be read and stored in a string. This is an inefficient way to store data now that we have ArrayBuffer and we'd like to not support this method.* –  Apr 24 '19 at 18:59
  • Right @Will that is what I was asking myself, I don't see how storing the data in an ArrayBuffer should be better, if you do so, but you need a string at the end to transmit the data you must do the conversion by yourself instead of using that API! So the only argument they had was storing in a string is bad which is not really true in all cases! – David Apr 24 '19 at 19:02
  • Strings are immutable. For big datastructures that is really ineffective. ArrayBuffers are mutable, and provide great ways to work with the underlying data through typed arrays. Also, Buffers can be shared (transfered without copying) between threads. – Jonas Wilms Apr 24 '19 at 19:09
  • Yes @JonasWilms, but you won't send an ArrayBuffer over the internet, wouldn't you? E-Mail clients for example send data base64 encoded, so you again need a string, if you don't have an efficient API you must convert the arrayBuffer to a string concatenating, now concatenate a 100MB arrayBuffer to a string, that blows up the RAM, that is the problem I'm not being able to pass through, readAsBinaryString was till now the only efficient way I found to get a string out of the blob. – David Apr 24 '19 at 20:00
  • Yes, the Buffer is definetly missing a `toString` method. – Jonas Wilms Apr 24 '19 at 21:22

1 Answers1

3

The history is that readAsBinaryString was present in an early specification of the FileReader API, before the ArrayBuffer interface exist.

When the ArrayBuffer interface appeared, readAsBinaryString has been deprecated because all its use cases could be done in a better way using that new interface.
Indeed, readAsBinaryString only converts the binary data into a DOMString (UTF-16). There is not much you can do from it afterward. Also, storing it as an UTF-16 string implies that it takes far more space in memory than the original data size. Add to this that strings are immutable, I guess you can see how inefficient it is to work from this.
And finally, if you really need to have this string, you can actually do the same from an ArrayBuffer, you just need to call String.fromCharCode over an Uint8 view of this ArrayBuffer.

// generate some binary data
document.createElement('canvas').toBlob(blob => {
  const bin_reader = new FileReader();
  const arr_reader = new FileReader();
  let done = 0;
  bin_reader.onload = arr_reader.onload = e => {
    if(++done===2) {
      const arr_as_bin = [...new Uint8Array(arr_reader.result)]
        .map(v => String.fromCharCode(v)).join('');
      console.log('same results: ', arr_as_bin === bin_reader.result);
      console.log(arr_as_bin);
    }
  }
  bin_reader.readAsBinaryString(blob);
  arr_reader.readAsArrayBuffer(blob);
});

Now, this method, while still very useless, has been re-added to the specs, because some websites did start using it.

And to help OP a bit more, since what they were trying to do was actually to get a base64 version of their Blob, then don't even use readAsArrayBuffer(), readAsDataURL() is what you need:

const blob = new Blob(['hello']);
const reader = new FileReader();
reader.onload = e => {
  const dataURL = reader.result;
  const base64 = dataURL.slice(dataURL.indexOf(',')+1);
  console.log(base64);
};
reader.readAsDataURL(blob);
Kaiido
  • 123,334
  • 13
  • 219
  • 285