How to get the status of an async function before it's finished?

549 Views Asked by At

I'm using NodeJs execFile() to start a daemon process. I've wrapped the callback in a promise to use it asynchronously in other parts of my application.

I understand callbacks emit err/result upon completion. So when the daemon process fails, the promise rejects the error correctly.

Problem: when the daemon process starts correctly, the promise doesn't resolve anything, since the callback has not completed yet.

The response is received once the daemon process is stopped since that is the end of the callback lifecycle. But that's too late.

Question: How do I track the life cycle of the callback to let the promise resolve(callback_in_progress)?

Do I need to use a node event module to create event listener?

These are 2 methods from the module. The first works well, but the second is where I'm having a problem.

const { execFile } = require('child_process');
const path = require('path');
const binaryPath = require('./BinaryPaths')

const mcUtil = path.join(binaryPath, 'multichain-util');
const mcd = path.join(binaryPath, 'multichaind');

module.exports = {
    createChain: (chainName) => {
        return new Promise((resolve, reject) => {
            execFile(mcUtil, ['create', chainName], (err, res) => {
               err ? reject(err) : resolve(res);
            });
        });
    },
    startMultichain: (chainName) => {
        return new Promise((resolve, reject) => {
           execFile(mcd, [chainName, 'daemon'], (err, res) => {
              err ? reject(err.message) : resolve(res);
           });
        });
     },
};
2

There are 2 best solutions below

0
UtkarshPramodGupta On

You can create a wrapper around your Promise to get state of your promise synchronously in your code, like so:

class StatefulPromise extends Promise {
  constructor (executor) {
    super((resolve, reject) => executor(
      (val) => {
        resolve(val)
        this._state = 'Resolved'
      },
      (err) => {
        reject(err)
        this._state = 'Rejected'
      },
    ))
    this._state = 'Processing'
  }

  get state () {
    return this._state
  }
}
 
// Create a promise that resolves after 3 sec 
var myStatefulPromise = new StatefulPromise((resolve, reject) => {
  setTimeout(() => resolve(), 3000)
})

// Log the state of above promise every 500ms
setInterval(() => console.log(myStatefulPromise.state), 500)

0
Roscoe van der Boom On

After searching more, I have found the solution to my problem posted in anouther thread. It was quite simple. I only needed to use spawn() instead of execFile(). This will stream data instead of only resolving once the callback is done.

Solution thread here: get execFile stdOut on chunks