Electron freezes while making PS-Node call, beginner need help!

Hi, I’m trying to check for certain processes running on a loop in electron. I originally was trying to do this in my react/electron app, but when I ran into problems just tried to do it in the main process of a simple electron app. Every time it makes the call the program hangs. Any advice would be greatly appreciated. Here is the relevant code:
app.on(‘ready’, function(){
createWindow();
setInterval(()=> {
checkP()
.then( (result) => console.log(result))
.catch((error) => console.log(error));
}, 5000);

  })

let checkP = () => {
  return new Promise(
    (resolve, reject) => {
      ps.lookup({command : 'Program X.exe'}, function(error, response){
        if (error) reject (error);
        resolve(response);
      })
    }
  )
}

So I have working code for you, and some suggestions on where to go with it.

First, the goodies:

app.on('ready', () => {
    createWindow();
    setInterval(() => {
        console.log("called!");
        ps.lookup({ command: "notepad.exe" }, (error, response) => {
            console.log("processed!");
            if (error) console.log(error);
            else console.log(response);
        });
    }, 5000);
});

I have tested this code in an example Electron app, and it works perfectly fine; no freezing to be seen. The only concern may be the latency between the call to the callback parameter provided to ps.lookup relative to the delay in interval.

Now back to the code you posted. I’ve listed some ideas below, accompanied with citations in your source snippet, which may help to clear up confusion and reduce problems such as these in the future.

app.on(‘ready’, function () { /* [2] */
    createWindow();
    setInterval(()=> {
        checkP() /* [0] */
        .then( (result) => console.log(result))
        .catch((error) => console.log(error));
    }, 5000);
});

/* [1] */
let checkP = () => {
    return new Promise( /* [3] */
        (resolve, reject) => {
            ps.lookup({command : 'Program X.exe'}, function(error, response) {
                if (error) reject(error); /* [4] */
                resolve(response); /* [5] */
            });
        }
    );
}

[0]: This function really gets in touch with the idea of event-driven programming. I like how you laid it out, and it’s certainly something I’d expect to see in Node source code.

[1]: I am not a fan of this function. There’s no need to create the function as a definition for a (what seems to be) global scope variable. Instead, why not just define it as a typical function? For example:

function checkP() {
    // ...
}

You did exactly that on [2].

In addition to the above, if you wish for your function to return a promise (either rejected or resolved) it’s best to declare your function as asynchronous. Maybe you just missed that on the shorthand definition (I know I do all the time).

async function testFn() { /* ... */ }
async () => { /* ... */ }

[3]: I personally have never seen a asynchronous function written this way. I’m certain it’s not bad practice or anything, just maybe this is something to think about as you review source code in the future.

[4] & [5]: I’m pretty sure in the context of your callback function, you are unable to use the variables reject and resolve. ps.lookup is going to take your callback parameter, and then call it in the code at some point later, such as the below:

// The ps.lookup function
function lookup(param, callback) {
    let error = null;
    let response = [];

    // use param to find matching processes

    // ...

    // check if there were any errors

    // ...

    // call callback function provided by user
    callback(error, response);
}

You can actually see this very thing happening in the source code for ps-node here: https://github.com/neekey/ps/blob/master/lib/index.js#L183

By the time the lookup function reaches that last line, and the control flow transfers to your callback function, the only variables your callback function can access are globals, local variables, and parameters. The variables you are trying to access in your code, which in this case are the functions reject and resolve, are only available in the scope of your checkP function; and thus cannot be accessed in the scope of your callback function.

All that being said, it is possible to change your checkP function to behave the way you are expecting, but it wouldn’t be a good way to solve this problem. checkP adds a level of indirection to the call chain for detecting processes that is unnecessary and troublesome for your application. A simple fix is to make the function provided to the setInterval function the same as your checkP function.

I don’t mean for anything I’ve said to seem condescending. Instead, I hope the effort expressed above in composing this post speaks to my respect for you and your journey with the projects you’re pursuing.

1 Like

I do not know why this post was flagged by someone, but it is honestly the kindest and most well thought out response I’ve ever gotten from a stranger so thank you so much.

I ended up solving the problem by using a different node library to check processes, “find-process” which has a built in promise function and has not given me any trouble. However, you response is still very useful from a learning perspective and I really appreciate you putting in the time/effort. Have a great holiday!

1 Like

I’m really happy to hear you ended up solving the problem.

Thank you for the kind words, they mean a great deal to me.

Happy holidays my friend. I hope you are well.

I want to quickly append some changes to my initial post.

Ignore citations [3], [4], and [5].

In JavaScript, there exists a concept called closures.

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

The code within the checkP function was fine.

When you provide a callback function (like you did for the ps.lookup call), that function is (presumably) created inline, with one of the closures referenced above. One thing I’d clarify in the Mozilla article is that the state of the outer variables are subject to change, and that change does indeed reflect within the execution of your inner functions; such as in the below example.

function genFn() {
  let msg = "Hello World!";
  let newFn = () => console.log(msg);
  msg = "Goodbye World!";
  return newFn;
}

let fn = genFn();
fn();

// result: "Goodbye World!"


(Credit: Abdur Rab Marjan on Medium - Link)

Apologies for the confusion.