Search code examples
javascriptnode.jses6-promise

Why are these .then() occurring out of order?


I've got a node application that spawns a child_process. When the child_process is finished running, I'd like to resolve a promise. The following code works, but the .then() statements occur out of order:

const storage = require('./storage');
const logging = require('./logging');
const process = require('child_process').spawn;


function convertIncomingFile(pathToFile) {
  logging.info(`Converting ${pathToFile}`);
  const convert = process(`cat`, [pathToFile], {});

  return Promise.resolve(
    convert.stdout.on('data', (data) => {
      logging.info(data.toString('utf8'));
    }),
    convert.stderr.on('data', (err) => {
      logging.error(err);
    }),
    convert.on('close', (code) => {
      logging.info(`Conversion finished with status code ${code}`);
    })
  );
}

module.exports = {
  convertFile: (filename) => {
    storage.downloadFile(filename).
      then((localFilename) => {
        logging.info(`File saved to: ${localFilename}`);
      }).
      then(() => convertIncomingFile(`./files/${filename}`)).
      then(() => {
        logging.info(`Coversion of ${filename} complete.`);
      }).
      catch((apiErr) => {
        logging.error(apiErr);
      });
  }
};

The output I get is:

info: File saved to: ./files/package.json
info: Converting ./files/package.json
info: Coversion of package.json complete.
info: {
 <file contents>
}

info: Conversion finished with status code 0

As you can see the Conversion of package.json complete. statement occurs before the file contents are logged and the conversion status code statement. Why is this the case and how do I get the 'Conversion complete' statement to come after the 'status code' statement?


Solution

  • Promise.resolve means return a solved value that you give it, it's not realy async as you expected. Check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise for more detailed info

    function convertIncomingFile(pathToFile) {
      logging.info(`Converting ${pathToFile}`);
      const convert = process(`cat`, [pathToFile], {});
    
      return new Promise((resolve, reject) => {
        convert.stdout.on('data', (data) => {
            logging.info(data.toString('utf8'));
          }),
          convert.stderr.on('data', (err) => {
            logging.error(err);
            reject()
          }),
          convert.on('close', (code) => {
            logging.info(`Conversion finished with status code ${code}`);
            resolve()
          })
      })
    }