13

I'm trying to refactor some code to remove .then pyramid and I need some help.

I'm trying to zip a JSON body to pass into a fetch call. I've actually managed this already, and called the fetch withing the zlib callback, but the code is becoming messy.

So, I've been looking at wrapping the zlib call in an async await wrapper. E.g.

async function syncCompressBody(body) {

  //return await compressBody(body);
  const compressedData = await compressBody(body);
  console.log("compressedData");
  console.log(compressedData);
  return compressedData;

}

function compressBody(body) {

  return new Promise( function( resolve, reject ) {

    zlib.deflate(body, (err, buffer) => {
      if(err){
        console.log("Error Zipping");
        reject(err);
      }
      console.log("Zipped");

      resolve(buffer);
    });
  });

}

The compressBody function returns a promise. The reject and resolve calls are in the callback of zlib.deflate.

I actually call syncCompressBody with the JSON to compress. The returned value is the result of the resolve call from compressBody.

The two functions are in a helper library. In my webpage, as part of the submit action, I have...

  console.log(jsonContent);
  const compressedBody = syncCompressBody(jsonContent);
  console.log(compressedBody);

  console.log("should be zipped by now..." + compressedBody);

However, the 'should be zipped' message is displayed before the 'zipped' message you can see in the compressBody function. What I actually want is for the code wait in syncCompressBody before returning to and resuming the JS in the submit action.

Edits following feedback....

Based on Bergi's and Liam's comments, I came up with this example of several awaits with each function relying on the previous function....

function awaitStyle2x(){
    console.log("pre-awaitStyle2 start");  
    (async () => {
      console.log("awaitStyle2 start")        
      const t = await theFirstAsyncFunctionX("pass it on");
      const u = await theNextAsyncFunctionX(t);
      const v = await aThirdAsyncFunctionX(u);
        console.log("awaitStyle2 finshed - " + v)
    })().catch(e => { /* handle the error */});   
    console.log("post-awaitStyle2 finished") ; 
}

The pre- comment is displayed first, then awaitStyle2 start, then the console log message in function theFirstAsyncFunctionX, then the post- message.

I can see now why my code has the race condition, am I on the right track?

Chris Adams
  • 1,376
  • 1
  • 8
  • 15
  • *`async function sync…`* cannot really make sense, can it? – Bergi Feb 28 '18 at 11:06
  • 1
    `compressedBody = await syncCompressBody(jsonContent);` – Liam Feb 28 '18 at 11:06
  • 2
    "*I actually call syncCompressBody, the returned value is the result*" - Nope. The returned value of an `async function` is a promise. Which only makes sense, as you cannot make zlib synchronous. You still need to wait for it. – Bergi Feb 28 '18 at 11:08
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Liam Feb 28 '18 at 11:09
  • @Bergi, yep naming not right. – Chris Adams Feb 28 '18 at 11:15
  • @Liam - You've prodded me there, I can't do that from the submit action as that isn't an async function, but you're right. I need to put the following actions into an async function, right? – Chris Adams Feb 28 '18 at 11:17
  • 1
    If you don't await you can't get a result. If you can't use await you need to handle the resulting promise or not wait for the result – Liam Feb 28 '18 at 11:22
  • Your code doesn't (and didn't have) a race condition, you we're trying to call async code synchronously. Your edit seems fine (from what I can see of your code) – Liam Feb 28 '18 at 13:34

1 Answers1

35

I had a similar use case with gzip, let me know if this helps:

const util = require('util');
const zlib = require('zlib');
const deflate = util.promisify(zlib.deflate);

console.log(jsonContent);
const compressedBody = await deflate(jsonContent);
console.log(compressedBody);

console.log("should be zipped by now..." + compressedBody);
Andrew
  • 1,590
  • 4
  • 19
  • 25