0

I'm writting a code in NodeJs using jimp and qrcode-reader. Those dependencies work well. The issue lies when I export the code into a module. And supposedly, it should return a value. This is an arrow function that returns the URL of the QR Code. However, If I use "console.log", I can see it works. But when I use the module, it returns undefined. Perhaps I'm missing something real simple.

Here is the code of the module:

const Jimp = require('jimp')
const fs = require('fs')
const QrCode = require('qrcode-reader')

const scanQR = (source) => {
const buffer = fs.readFileSync(source)

   Jimp.read(buffer, (err, image) => {
       try {
           const qr = new QrCode()
           qr.callback = (error, value) => {
               try {
                   console.log(value.result)
                   return value.result
               } catch(error) {
                   console.error(error)
               }
           }
           qr.decode(image.bitmap)
       } catch (error) {
           console.error(error)
       }
   })
}

module.exports = scanQR

Here is the module imported:

const scanQR = require('./utils/scanQR')
const qr_code_screenshot = `${__dirname}/assets/images/qrcode-test.png`
const result = scanQR(qr_code_screenshot)
console.log(result)

Here is the result on console: Console result

Thanks in advance.

  • Because you're performing asynchronous operations and not returning properly. You are doing `return value.result` but that's inside a callback, which itself is never returned. You probably want to wrap this in a promise, and resolve the promise instead. – Terry Feb 27 '22 at 21:59
  • Thanks Terry. So, Should I use Promise instead of "qr.callback"? Is that what you mean when wrapping the return? – José Rafael Moro Galindo Feb 27 '22 at 22:08

1 Answers1

1

Your scanQR function is not returning anything: and therefore when you assign its return value, you get undefined. That is expected. The issues comes from you attempting to returning something inside a callback that is only fired asynchronously.

To solve this issue you will need to wrap the inner logic in a promise (which is returned). Then, you can resolve/reject the promise based on whether the code was successfully executed, or threw an error:

const scanQR = (source) => {
    // Wrap all logic inside a promise, which you return
    return new Promise((resolve, reject) => {
        const buffer = fs.readFileSync(source);

        Jimp.read(buffer, (err, image) => {
            try {
                const qr = new QrCode();
                qr.callback = (error, value) => {
                    try {
                        // Resolve promise here
                        resolve(value.result);
                    } catch(error) {
                        // Reject promise
                        reject(error);
                    }
                }
                qr.decode(image.bitmap);
            } catch (error) {
                reject(error);
            }
        });
    });
}

When consuming the module, you will need to either use .then():

const scanQR = require('./utils/scanQR');
const qr_code_screenshot = `${__dirname}/assets/images/qrcode-test.png`;

// `scanQR` returns a promise and you will need to use `.then()`
scanQR(qr_code_screenshot).then(data => console.log(data));

...or use async/await: here is one of the many ways to do it:

const scanQR = require('./utils/scanQR');

async function scan(image) {
    const result = await scanQR(image);
    console.log(result);
}

scan(`${__dirname}/assets/images/qrcode-test.png`);
Terry
  • 63,248
  • 15
  • 96
  • 118