Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fetch resource, compute hash, return promise

I would like to use the Fetch API in a browser extension to download a resource and compute a hash thereof. The following works (using crypto through Browserify)

fetch(url).then(function(response) {
  return response.blob();
}).then(function(data) {
  var a = new FileReader();
  a.readAsBinaryString(data);
  a.onloadend = function() {
    var hash = crypto.createHash(hashType);
    hash.update(a.result, 'binary');
    return hash.digest('hex');
  };
})

but has the disadvantage that I have to wait for a.onloadend while the context in which I'd like to embed it requires a Promise to be returned. Also, it seems quite weird to first fetch the entire blob, then read it into a FileReader just to dump it into createHash afterwards.

Any hints?

like image 863
Nico Schlömer Avatar asked Sep 26 '22 02:09

Nico Schlömer


2 Answers

The crypto hash.update method also takes a buffer, so there is no need to make a detour via a FileReader. Just do

fetch(url).then(function(response) {
    return response.arrayBuffer();
}).then(function(arrayBuffer) {
    var buffer = require('buffer')(new Uint8Array(arrayBuffer));
    var hash = require('crypto').createHash(hashType);
    hash.update(buffer, 'binary');
    return hash.digest('hex');
})

If that doesn't work, you can easily promisify a FileReader:

function getResult(reader) {
    return new Promise(function(resolve, reject) {
        reader.onload = function() {
            resolve(this.result);
        };
        reader.onerror = reader.onabort = reject;
    });
}

and use it like this:

fetch(url).then(function(response) {
    return response.blob();
}).then(function(data) {
    var a = new FileReader();
    a.readAsBinaryString(data);
    return getResult(a);
}).then(function(result) {
    var hash = crypto.createHash(hashType);
    hash.update(result, 'binary');
    return hash.digest('hex');
})
like image 153
Bergi Avatar answered Oct 03 '22 14:10

Bergi


I think what you're asking for here is promise chaining. You can create a promise inside the then handler and return it.

var yaypromise = fetch(url).then(function(response) {
  return response.blob();
}).then(function(data) {
  return new Promise(function(resolve, reject){
      var a = new FileReader();
      a.readAsBinaryString(data);
      a.onloadend = function() {
        var hash = crypto.createHash(hashType);
        hash.update(a.result, 'binary');
        resolve(hash.digest('hex'));
      };  
  });
})

And then yaypromise is probably the promise you're looking for. It will resolve with hash.digest('hex')

like image 27
david Avatar answered Oct 03 '22 14:10

david