0

I am having a class where I am using node-schedule's bind()-function to create a job queue:

class Test {

    constructor() {}

    schedulerLog(value) {
        this.ipcRenderer.send('job-log', process.pid + ': ' + value);
    }

    async initScheduler() {

        try {
            let dt = new Date(el.scheduled_time)
            let db = this.knex // one knex instance per scheduled job

            this.schedule.scheduleJob(dt, function () {
                // When job is running update the status of the job in the db
                let sc = new ScheduledContent(db)
                el.status = "sent" // set status to "sent"

                sc.createOrUpdateContent(el.id, el.title, null, el.scheduled_time, el.image, el.status).then((res) => {
                    schedulerLog('Job-ID #' + el.id + ' -- ' + el.title + ' -- executed at: ' + dt + " -- and updated: " + res);
                })
            }.bind(null, [db, schedulerLog]));
            this.schedulerLog("\n Number of Jobs Scheduled: " + Object.keys(this.getQueue()).length + "\n");
        } catch (error) {
            this.schedulerLog(error);
        }
    }
}

module.exports = {
    Test
};

However, when using .bind(null, [db, schedulerLog]) I get an error:

ReferenceError: schedulerLog is not defined

Any suggestions how I still can bind the function within my class to the queue?

I appreciate your replies!

Carol.Kar
  • 4,581
  • 36
  • 131
  • 264
  • 2
    You define a function and use `.bind` to supply parameters to it but...the function doesn't take parameters. – VLAZ May 10 '19 at 20:15
  • 1
    use `.bind(this)` and then refer to `this.schedulerLog()` inside the arrow function. – Alnitak May 10 '19 at 20:17
  • 3
    Should `.bind(null, [db, schedulerLog])` be `.bind(null, [db, this.schedulerLog])`? If you're not using arrow functions, you might also consider binding `schedulerLog` in the constructor as well. i.e. `this.schedulerLog = this.schedulerLog.bind(this)` – Khauri May 10 '19 at 20:18
  • 2
    There is no `schedulerLog`, you need to use `this.schedulerLog`, eg: `.bind(null, [db, this.schedulerLog]));` – Titus May 10 '19 at 20:18
  • 3
    OK, I'm confused - why do you even have `bind` here? It doesn't take parameters and it is in scope with the things you try to bind to it. So you don't need to bind anything aside from maybe the `this` context. – VLAZ May 10 '19 at 20:19
  • 1
    @KhauriMcClain and Titus - how is that going to change the fact that the function doesn't take any parameters. And even if it did, it's passed in an array, instead of separate parameters, so it won't even receive a parameter called `schedulerLog` unless it did destructuring on the array. – VLAZ May 10 '19 at 20:21
  • 1
    `bind` has nothing to do with node-schedule. It's a native method on functions. – melpomene May 10 '19 at 20:21
  • @melpomene right, I was also confused about that. OP says they want to use `.bind` for the scheduling but there is no need for either to use `.bind` in order to schedule something or `.bind` to do partial application. – VLAZ May 10 '19 at 20:22
  • @VLAZ It doesn't, but it would make the OP's immediate error go away (the subject of the question). And OP could of course add parameters to the function if they desired. I'm trying not to make too many assumptions about the nature of their code. – Khauri May 10 '19 at 20:24
  • @VLAZ I was addressing the error and he uses a normal function which has `arguments` – Titus May 10 '19 at 20:24
  • The reason I use bind is that I want to use current data in with the scheduler: https://www.npmjs.com/package/node-schedule#date-based-scheduling – Carol.Kar May 10 '19 at 20:25
  • @Titus there is no `arguments` in that code. There is nothing that uses any supplied parameters. So I'm not convinced how fixing the immediate error helps when the whole approach seems incorrect. – VLAZ May 10 '19 at 20:26
  • @Anna.Klee But you're not changing the variables you bind. If you don't change your variables, there's no need to make a copy (which is what bind does). – melpomene May 10 '19 at 20:26
  • If I am using `.bind(null, [this, db]));`, I am getting `Uncaught TypeError: Cannot read property 'schedulerLog' of null` – Carol.Kar May 10 '19 at 20:29
  • @melpomene If I am leaving bind away, and simply code: ` this.schedulerLog("test") })` I get: `Uncaught TypeError: this.schedulerLog is not a function` – Carol.Kar May 10 '19 at 20:33
  • Because `this` is going to be *doubly* wrong at that point - the first callback you have has its own `this`, as does the second callback. – VLAZ May 10 '19 at 20:41
  • Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – VLAZ May 10 '19 at 20:41
  • @VLAZ @melpomene There are lots of errors/problems in this code. `el` is undefined. `this.ipcRenderer` is undefined. an `async` function is used but no `await` in sight. Wrapping a promise with a try-catch instead of using the `.catch` method. Make sure you address all of this when you write your answer. – Khauri May 10 '19 at 20:42
  • Sounds like it would be most easily fixed by passing an arrow function to `scheduleJob` (as in `...scheduleJob(dt, () => { ... })`). – melpomene May 10 '19 at 20:43
  • @KhauriMcClain that would make it too broad or OT for MVCE reasons. However, as it stands, it turns out OP's problem was a dupe, so I went with that as my answer. – VLAZ May 10 '19 at 20:54

1 Answers1

0

There's no reason to use bind here, and especially none to bind an array of arguments that you never use. Also, schedulerLog is a method, a property of this, not a local variable - that's why you get an exception. All you need to do is use a closure, and arrow functions to keep the this context:

initScheduler() { // no need for async here

    try {
        let dt = new Date(el.scheduled_time)
        let db = this.knex

        this.schedule.scheduleJob(dt, async () => { // arrow function!
            let sc = new ScheduledContent(db)
            el.status = "sent"

            let res = await sc.createOrUpdateContent(el.id, el.title, null, el.scheduled_time, el.image, el.status)
//                    ^^^^^ use async/await instead of .then() here
            this.schedulerLog('Job-ID #' + el.id + ' -- ' + el.title + ' -- executed at: ' + dt + " -- and updated: " + res);
//          ^^^^^ call method on this
        });
        this.schedulerLog("\n Number of Jobs Scheduled: " + Object.keys(this.getQueue()).length + "\n");
    } catch (error) {
        this.schedulerLog(error);
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375