0

I am trying to return a json report (containing two parts) as javascript object in my mainFile.js as shown below:

file1.js

module.exports = async (param1, param2) => {
    try {
        await fun1(param1, param2);
        await fun2();

        const resp = await generateReport();

        await fun3();

        // console log works fine in here.
        console.log(resp);
        return resp;

      } catch (err) {
        handleError(err);
      }
}

where fun1(), fun2(), fun3() do irrelevant stuff and generateReport() is shown below:

generateReport = () => {
    return new Promise((resolve, reject) => {
        console.log("Generating report.");
        core.jsonreport((err, resJSON1) => {
            if (err) {
                throw new Error(`Error: ${err.message}`);
            } else {
                core.jsonreport2((err, resJSON2) => {
                    if (err) {
                        throw new Error(`Error: ${err.message}`);
                    } else {
                        resolve(
                            JSON.stringify({
                                part1: resJSON1,
                                part2: resJSON2
                            }, null, 4));
                    }
                })
            }
        });
    })
}

but when I require and call that function in my main file I get no output.

mainFile.js

const myFunc = require('./file1');

myFunc(param1, param2)
 .then(res => console.log(res));
// Console log didn't work here.

Any ideas how I could fix that?

This is the code of the jsonreport function that I need to use.

core.js file from a package I am using.

/**
 * Generates a report in JSON format
 **/
Core.prototype.jsonreport = function (callback) {
  if (typeof callback === 'function') {
    this.api.requestOther('/core/other/jsonreport/', callback);
    return;
  }
  return this.api.requestPromiseOther('/core/other/jsonreport/');
};
Kostas Letros
  • 53
  • 1
  • 11
  • I'm not sure why, but `myFunc` (in `file1.js`) returns a function, so you need to call it as `myFunc(param1, param2)().then(res => console.log(res));` – Robin Zigmond Nov 25 '20 at 20:33
  • 1
    actually no, because the outer function is also `async`, so you can't call the result directly. It would need to be `myFunc(param1, param2).then(f => f().then(res => console.log(res)))`. At this point I'm really questioning why `myFunc` is the way it is... – Robin Zigmond Nov 25 '20 at 20:35
  • Sorry, my bad. That was because of something I was trying.. – Kostas Letros Nov 25 '20 at 20:38
  • 3
    Don't ever `throw` from an asynchronous callback. Instead, `reject()` the promise with the error. – Bergi Nov 25 '20 at 20:42
  • 1
    Also, you should [promisify](https://stackoverflow.com/q/22519784/1048572) the `jsonreport` and `jsonreport2` functions separately. Then write `generateReport` as an `async function` as well. – Bergi Nov 25 '20 at 20:44

2 Answers2

1

Your code could look way better (and may be less buggy) like this:

const {
  promisify
} = require('util');
const { core } = require('...');
const { jsonreport, jsonreport2 } = core;

const promisifiedJsonreport = promisify(jsonreport).bind(core);
const promisifiedJsonreport2 = promisify(jsonreport2).bind(core);

generateReport = () => {
  console.log("Generating report.");

  const errorHandler = err => {
    throw new Error(`Error: ${err.message}`);
  };

  return Promise.all([promisifiedJsonreport(), promisifiedJsonreport2()])
  .catch(errorHandler)
  .then(([resJSON1, resJSON2]) => JSON.stringify({
      part1: resJSON1,
      part2: resJSON2
    }, null, 4));
}

Using promisify and Promise.all are good choices for you because:

  • You need to return a Promise (for subsequent await), and it's usually better to compose with existing promises than creating one yourself with new Promise
  • The two asynchronous calls don't depend on each other
  • The error handler is the same for the two calls
  • You need to retrieve the two values of the asynchronous calls at the end

Using promises (more than making your code look better) will also allow the errors to be properly caught by the caller.

Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • Thanks! But I get an error now. I edited my question to add the corresponding code. Generating report. TypeError: Cannot read property 'api' of undefined at Core.jsonreport (/home/kali/Desktop/Project/node_modules//src/core.js:931:10) at internal/util.js:297:30 at new Promise () – Kostas Letros Nov 26 '20 at 09:49
  • As the errors are now properly caught, you have the explanation on why your code didn't work. The error seems to be related to some library that you are using. If you can't fix it, that's another topic, you can open a new question about it, or an issue to the library editor. – Guerric P Nov 26 '20 at 09:56
  • If you check the link: https://masteringjs.io/tutorials/node/promisify , at the bottom there is a `Losing Context` paragraph, which might explain the reason why this code didn't work. I think it has to do with the fact that the library is using the `this` keyword. – Kostas Letros Nov 26 '20 at 10:22
  • Adding a `.bind(core)` call after `promisify(jsonreport)` to keep the context unmodified, fixed the issue. Thanks for everything! – Kostas Letros Nov 26 '20 at 10:36
  • Okay, I've edited my answer, feel free to submit an edit to my answer with the imports of the library! – Guerric P Nov 26 '20 at 11:05
-1

I don't know what should do code inside generateReport but the error is probably there. If I simplify code, it's ok:

generateReport = () => {
    return new Promise((resolve, reject) => {
        resolve("Result");
    })
};

const myFunc = async (param1, param2) => {
    try {
        return await generateReport();
      } catch (err) {
        handleError(err);
      }
};

myFunc("A", "B").then(res => console.log(res));

You need to focus on jsonreport and jsonreport2.

jrck
  • 119
  • 1
  • 2
  • 6