Asymptotic complexity of slicing/merging blobs

487 views Asked by At

I want to work heavily with JavaScript blobs. But I'm not sure about performance of some operations. So in this simple example...

let n = 10; // not a constant :-)
let blob = e.dataTransfer.files[0]; // some file from user...

let blob1 = blob.slice(0, n); // O(1) or O(n)?
let blob2 = blob.slice(n); // O(1), O(n), O(blob2.length) or O(blob.length)?
let merged = new Blob([blob1, blob2]); // O(1) or O(blob.length)?

URL.createObjectURL(merged); // O(blob.length) - just to ensure, that blob will be used...

I'm interested in both time and space complexity.

1

There are 1 answers

4
Dima Kurilo On BEST ANSWER

Each function has different implementation for each engine.
For WebKit you can check slice here:
https://github.com/WebKit/webkit/blob/master/Source/WebCore/platform/network/BlobRegistryImpl.cpp#L182
For Firefox it's somwhere here:
https://hg.mozilla.org/mozilla-central/file/d8e238b811d3/dom/file
Also it can be changed with new version.
So the best way is to try with the real data in real browsers and to measure results. Then you will be able to decide.

And as I see from source code for WebKit, Blob.slice is O(blob.length) even if you have startIndex and endIndex.
Blob([b1,b2..]) is O(b1.length + b2.length + ...)
But URL.createObjectURL is just generate link to Blob, so it's O(1).

Blob is immutable, so every time you are changing Blob you are creating new one. That's why you can't just get reference to part of Blob with slice.

To play with Blobs I created this code:

var container = document.getElementById('container');
var getReaderPromise = function(bl) {
  var blReader = new FileReader();
  return new Promise(function(resolve, reject) {
    blReader.onload = function() { resolve(blReader.result) };
    blReader.readAsArrayBuffer(bl);
  });
}

var showContent = function(arrbuf) {
  console.log(String.fromCharCode.apply(null, new Uint8Array(arrbuf)));
}

var foo = new Blob('abcdefghjklmnopqrstuvwxyz'.split(''), {type : 'text/plain'});
var promiseFoo = getReaderPromise(foo);
var foores = undefined;
promiseFoo.then(function(res) {
  foores = res;
});

var bar1 = foo.slice(2,10);
var promiseBar1 = getReaderPromise(bar1);
var bar1res = undefined;
promiseBar1.then(function(res) {
  bar1res = res;
});

var bar2 = foo.slice(12,20);
var promiseBar2 = getReaderPromise(bar2);
var bar2res = undefined;
promiseBar2.then(function(res) {
  bar2res = res;
});

var bars = new Blob([bar1, bar2]);
var promiseBars = getReaderPromise(bars);
var barsres = undefined;
promiseBars.then(function(res) {
  barsres = res;
});

Promise.all([promiseFoo, promiseBar1, promiseBar2, promiseBars]).then(function() {
  showContent(foores);
  showContent(bar1res);
  showContent(bar2res);
  showContent(barsres);

  var bar2arr = new Uint8Array(bar2res);
  bar2arr[4] = '2'.charCodeAt();

  showContent(bar2res);
  showContent(barsres);
  showContent(foores);


  var url = URL.createObjectURL(bars);
  console.log(url);
  container.innerHTML += '<iframe src="' + url + '"></iframe>';
  var barsarr = new Uint8Array(barsres);
  barsarr[4] = '5'.charCodeAt();
  container.innerHTML +=  '<iframe src="' + url + '"></iframe>';
  url = URL.createObjectURL(bars);
  console.log(url);
  container.innerHTML += '<iframe src="' + url + '"></iframe>';
});

(http://www.kurilo.su/stackoverflow/46085675/)
You can try to open it in different browsers and will find that Blob is immutable in any browsers.
So slice and merge can't be O(1). At least O(n), but as I can see in WebKit it's O(blob.length).