0

Desperately trying to write a sync version of https://www.npmjs.com/package/node-firebird#reading-blobs-aasynchronous

Basically I need to (a)wait twice:

  1. for the callback function to execute so that the eventEmitter is available
  2. for the "end" event to occur

and then return the Buffer.

my code (JS/TS mix for now) currently does 2, but not 1 : readBlob returns undefined, then Buffer.concat(buffers) is called later ... :

function readBLOB(callback: any): Buffer {
    return  callback(async (err, _, eventEmitter) => {
        let buffers = []
        if (err)
            throw err

        eventEmitter.on('data', chunk => {
            buffers.push(chunk);
        });
        return await eventEmitter.once('end', function (e) {
            return Buffer.concat(buffers)
        })
    })
}

Sorry to ask one more time (yes, I checked a lot of other questions and tried a lot of things...), but how to make this work (simply...) ?

(the function that calls the callback is fetch_blob_async in https://github.com/hgourvest/node-firebird/blob/master/lib/index.js#L4261 , just in case...)

Dr. Goulu
  • 580
  • 7
  • 21
  • 2
    You can't make an async function execution sync how much you ever wanted to. It's just simply not possible. You've to adapt "asynchronous thinking", and design your code to make a benefit of asynchronicity instead of keeping stuck in synchronous design. – Teemu Dec 11 '20 at 11:59
  • 1
    You can, however, make it return a Promise which resolves to a Buffer, if that suits you (still async, but you can `const buf = await readBlob()`) Take a look at [this answer](https://stackoverflow.com/a/34736837/1913729) which transforms a callback function into one that returns a Promise – blex Dec 11 '20 at 12:02
  • ok.. you said you want to await an event once more.. so the `asyncLoop` would go over until what you define as a `success` or a `fail` – The Bomb Squad Dec 11 '20 at 12:58
  • @Teemu, you're right. Most of my code is async, based on StencilJS (or rather TS) web components and a node express server. My "only" problem is : how to send res.status(200).json(rows||{}) when rows contain some BLOB fields that are returned async by the node-firebird package ? at this point I need all the content of rows to be sync in order to be sent... – Dr. Goulu Dec 14 '20 at 12:59

1 Answers1

2

There are few mistakes here like returning an callback function, witch returns, i guess, undefined or returning something IN an callback function that makes no sense.

Also async / await makes no sense here it has no effect. async / await is only useful if you want to await till some Promise resolves. But you have no Promise in your code at all.

What you need is new Promise

function readBLOB(callback) {
  return new Promise((resolve, reject) => {
    callback((err, _, eventEmitter) => {
      let buffers = [];
      if (err) reject(err);
      eventEmitter.on("data", chunk => {
        buffers.push(chunk);
      });
      eventEmitter.once("end", function(e) {
        resolve(Buffer.concat(buffers));
      });
    });
  });
}

Simple like that. You resolve your Buffer and reject if some error occurs

Now you can use it like:

readBLOB(cb).then(data => {
   console.log(data);
})
bill.gates
  • 14,145
  • 3
  • 19
  • 47