1
votes

I have a function that performs long computation and once done invokes a callback function that is passed as parameter. I am querying this function within Koa router and need to return to the browser the results of long computation. Function comes from a library and I am not able to change its interface (i.e. I can change the code of the callback but I can't change someLongComputation to return a promise)

Current code sets ctx.body immediately as someLongComputation returns immediately. Any idea how I can wait until the callback is called and only then set the ctx.body with the results from the callback.

router.post(`/abc`, async (ctx) => {
  try {
      someLongComputation(function(err, res) {
          if(err) {
              console.log(err);
          }
      }
      ctx.body = {
        status: 'success',
        data: {'res' : ""}, 
        errors: []
      };
  } catch (err) {
      console.log(err)
  }
})
2
Yes you can change someLongComputation() to use a promise: require('util').promisify(someLongComputation) returns a version of the function you can await.Patrick Roberts
For simplicity I have omitted the actual name of the someLongComputation function. I am trying to do it with graphicsmagic stream function that is run after a resize: gm(request(photo)).resize(size[0], size[1]).stream . Using promisify on that code seems to return errors: TypeError: format.split is not a functionuser1217406

2 Answers

2
votes

If you want to use async/await and assuming the longcomputation function can return a promise you can change your code to await the return of the function.

router.post(`/abc`, async (ctx) => {
  try {
    const result = await someLongComputation();
    // do whatever you want with result

  } catch (err) {
    console.log(err)
  }
})

The other option is to use the variable in the callback of the function

router.post(`/abc`, async (ctx) => {
  try {
    someLongComputation(function(err, res) {
      if(err) {
          console.log(err);
      }
      //moved setting the body to inside the callback for the computation
      ctx.body = {
        status: 'success',
        data: {'res' : ""}, 
        errors: []
      };
    }
  } catch (err) {
    console.log(err)
  }
})
1
votes

You have two options.

1. Send response from your callback

router.post(`/abc`, async (ctx) => {
  try {
    someLongComputation(function(err, res) {
      if (err) {
        console.log(err);
        // you might want to send error response here
      }
      // send response from callback
      ctx.body = {
        status: 'success',
        data: { res: '' },
        errors: []
      };
    });
  } catch (err) {
    console.log(err);
    // you might want to send error response here as well
  }
});

2. Create a promise out of your library function and use async/await

const doLongComputation = () => {
  return new Promise((resolve, reject) => {
    try {
      someLongComputation(function(err, res) {
        if (err) {
          console.log(err);
          reject(err);
        }
        resolve(res);
      });
    } catch (err) {
      console.log(err);
      reject(err);
    }
  });
};

router.post(`/abc`, async (ctx) => {
  try {
    const res = await doLongComputation();
    ctx.body = {
      status: 'success',
      data: { res: '' },
      errors: []
    };
  } catch (err) {
    console.log(err);
    // send error response here
  }
});