Async function - getting error: TypeError: is not a constructor

Can we use "async function" in Node-RED?

This works at the command line:

node myAsyncFunctionTest.js

const Slack = require('slack'); // https://www.npmjs.com/package/slack
let token = "blahblah-redacted";
let localDebug = true;

let slackUserId = "U2B0ZF78F";

async function slackGetUsersInfo(slackUserId) {
  try {
    if (localDebug) {
      console.log("slackGetUsersInfo slackUserId: " + slackUserId);
    }
    let slack = new Slack({ token });
    let user = slackUserId;
    let res = await slack.users.info({ "token": token, "user": user }); // https://api.slack.com/methods/users.info

    if (localDebug) {
      console.log("slackGetUsersInfo res: " + JSON.stringify(res, null, 2));
    }

    //msg.payload.slackUserInfo = res;
    //console.log("msg.payload.slackUserInfo" + JSON.stringify(msg.payload.slackUserInfo, null, 2));
    //return msg;
    //node.send({msg});
  } catch (err) {
    console.error(err);
  }
}
//module.exports.slackGetUsersInfo = slackGetUsersInfo;

slackGetUsersInfo(slackUserId)

But similar code in Node-RED fails:

const Slack = global.get('slackModule'); // https://www.npmjs.com/package/slack
let token = "blahblah-redacted";
let localDebug = true;

let slackUserId = msg.payload.user;

async function slackGetUsersInfo(slackUserId) {
  try {
    if (localDebug) {
      console.log("slackGetUsersInfo slackUserId: " + slackUserId);
    }
    let slack = new Slack({ token });
    let user = slackUserId;
    let res = await slack.users.info({ "token": token, "user": user }); // https://api.slack.com/methods/users.info

    if (localDebug) {
      console.log("slackGetUsersInfo res: " + JSON.stringify(res, null, 2));
    }

    msg.payload.slackUserInfo = res;
    console.log("msg.payload.slackUserInfo" + JSON.stringify(msg.payload.slackUserInfo, null, 2));
    //return msg;
    node.send({msg});
  } catch (err) {
    console.error(err);
  }
}
//module.exports.slackGetUsersInfo = slackGetUsersInfo;

slackGetUsersInfo(slackUserId)

I do have settings.js using:

   functionGlobalContext: {
    slackModule:reguire('slack')
   }

However, it produces and error:

TypeError: Slack is not a constructor
** at slackGetUsersInfo (Function node:a516cf8f.18641 [slackGetUsersInfo]:15:17)**

Question:
Can we use an async function in Node-RED?

If callback function is available, have you tried that?

I'm not certain if async await is possible. You could search this forum for async await.

I did search for: async await
Long ago I stopped writing "callback" and ".then" style Javascript.
I have a rather large library of my personal code snippets using "async await" style at this point.
I have no interest nor time in refactoring to go back to "callback hell".
This is why I am specifically asking:
Question:
Can we use an async function in Node-RED?

My apologies, I assumed you wanted that particular code to work not just academically interested in whether async await worked.

It was just a suggestion.

I asked this on the Slack a while ago, and @knolleary responded (and feel free to correct me again), that with NR now requiring a minimum of NodeJS v8.5, there is no reason not to use ES6+ in your code, both for function nodes as well as custom nodes. Async functions should be compatible with Node v8.5 from my own research, but I’m not sure in what context function nodes are executed, so have you tried checking the source of that node yet?

Yes you can use async functions in the Function node.

But that is unrelated to the error you are hitting. For some reason the object returned by const Slack = global.get('slackModule') is not a function.

I've just tried requiring that module and using it in the Function node and it worked fine for me.

I note you have this:

 functionGlobalContext: {
    slackModule:reguire('slack')
   }

Is reguire just a copy and paste error or is that from your actual settings file?

Can you add console.log(Slack) after the global.get line to see what it is returning?

Hawk eye!

Well, I did have a typo and corrected that, thank you for pointing that out!

settings.js looks like this now:

root@raspberrypi:/opt# tail -13 /opt/hassio/homeassistant/node-red/settings.js
    // Customising the editor
    editorTheme: {
        projects: {
            // To enable the Projects feature, set this value to true
            enabled: false
        }
    },

   functionGlobalContext: {
    slackModule:require('slack')
   }

}

I added logging to the script:

console.log("##########");
const Slack = global.get('slackModule'); // https://www.npmjs.com/package/slack
console.log(Slack);
console.log("##########");
let token = "xoxb-blahblah-redacted";
let localDebug = true;

let slackUserId = msg.payload.user;

async function slackGetUsersInfo(slackUserId) {
  try {
    if (localDebug) {
      console.log("slackGetUsersInfo slackUserId: " + slackUserId);
    }
    let slack = new Slack({ token });
    let user = slackUserId;
    let res = await slack.users.info({ "token": token, "user": user }); // https://api.slack.com/methods/users.info

    if (localDebug) {
      console.log("slackGetUsersInfo res: " + JSON.stringify(res, null, 2));
    }

    msg.payload.slackUserInfo = res;
    console.log("msg.payload.slackUserInfo" + JSON.stringify(msg.payload.slackUserInfo, null, 2));
    //return msg;
    node.send({msg});
  } catch (err) {
    console.error(err);
  }
}

slackGetUsersInfo(slackUserId)

I get / see undefined
console.log(Slack)

14 Jul 08:37:34 - [info] [mqtt-broker:core-mosquitto] Connected to broker: mqtt://core-mosquitto:1883
14 Jul 08:37:34 - [info] [slack-config:Perceptron] connected to slack with token: xoxb-450...wFC
14 Jul 08:37:39 - [info] [server:Home Assistant] WebSocket Connected to http://hassio/homeassistant
##########
undefined
##########
slackGetUsersInfo slackUserId: U1B9ZF78E
TypeError: Slack is not a constructor
    at slackGetUsersInfo (Function node:a516cf8f.18641 [slackGetUsersInfo]:16:17)
    at Function node:a516cf8f.18641 [slackGetUsersInfo]:33:1
    at Function node:a516cf8f.18641 [slackGetUsersInfo]:35:3
    at Script.runInContext (vm.js:133:20)
    at FunctionNode.<anonymous> (/opt/node_modules/@node-red/nodes/core/core/80-function.js:230:33)
    at FunctionNode.emit (events.js:198:13)
    at FunctionNode.Node.receive (/opt/node_modules/@node-red/runtime/lib/nodes/Node.js:237:14)
    at SwitchNode.Node.send (/opt/node_modules/@node-red/runtime/lib/nodes/Node.js:224:14)
    at applyRules (/opt/node_modules/@node-red/nodes/core/logic/10-switch.js:441:42)
    at applyRule (/opt/node_modules/@node-red/nodes/core/logic/10-switch.js:224:17)

I do have the slack npm module installed as seen in package.json
"slack": "^11.0.2",

Is my settings.js not correct?
or is something wrong with how I called:
const Slack = global.get('slackModule'); // https://www.npmjs.com/package/slack

Thank you,
Ernest

My apologies, I assumed you wanted that particular code to work not just academically interested in whether async await worked.

It was just a suggestion.

Hey Steve-Mcl, no apologies needed!
Just trying to clarify the ask :slight_smile:

Can you confirm the slack package is installed in the node_modules folder under where node-red runs from?

Or did you npm -g?

It is indeed installed and I tested the script via cli and it works:
node myAsyncFunctionTest.js

Can you share the log output from Node-RED when it starts up? That will confirm what settings file it is using. If you really did have that typo in the file when you tried before, then Node-RED would have reported it and refused to start. This makes me thing it is using a different settings file.

OMG, I needed to restart for settings.js to work!
That was it!
:man_facepalming:
Doh!
Thank you!

Created a pull request to update the docs: