Множественный вызов ссылочной функции (Callback must be a function. Received undefined)

Рейтинг: 0Ответов: 1Опубликовано: 02.05.2023

Имеется следующий код:

function test () {
    this.defaultCallback = {}
    this.setCallback = function (callback) {
        this.defaultCallback = callback
    }
    this.getDataIntervally = function () {
        // get data
        let data = 'baz'
        setInterval(this.defaultCallback(data), 1000)
    }
} 

function bar (data) {
    // do something with data
    console.log(data)
}

let a = new test()
a.setCallback(bar)
a.getDataIntervally()

После инициализации экземпляра test в поле defaultCallback присваивается внешняя функция bar. Однако при попытке вызова в test функции getDataIntervally обращение к функции bar происходит только первый раз, остальные вызывают Exception. Ниже лог:

baz  // первый успешный вызов функции
node:internal/validators:224
    throw new ERR_INVALID_CALLBACK(callback);
    ^

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
    at setInterval (node:timers:210:3)
    at testclass.foo (C:\Users\user\www\infocenterv2\test.js:9:9)
    at Object.<anonymous> (C:\Users\user\www\infocenterv2\test.js:20:3)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)        
    at node:internal/main/run_main_module:17:47 {
  code: 'ERR_INVALID_CALLBACK'
}

Кто-то сталкивался с подобной ошибкой?

Ответы

▲ 1Принят

setInterval(this.defaultCallback(data), 1000)

В такой конструкции в setInterval первым аргументом передаётся результат выполнения this.defaultCallback(data), а должна передаваться ссылка на функцию.

Делайте вот так:

function test() {
  this.defaultCallback = undefined;
  this.setCallback = (callback) => {
    this.defaultCallback = callback;
  };
  this.getDataIntervally = () => {
    let data = 'baz';
    setInterval(() => this.defaultCallback(data), 1000);
  };
}

function bar(data) {
  console.log(`<bar> data="${data}"`);
}

let a = new test();
a.setCallback(bar);
a.getDataIntervally();

И используйте "стрелочные функции", чтобы не терять контекст.


Вопрос: сильно ли изменится код при использовании конструкции class с геттерами и сеттерами?

Ответ:

class Test {
    #__defaultCallback;
    get defaultCallback() {
        return this.#__defaultCallback;
    }
    set defaultCallback(fn) {
        this.#__defaultCallback = fn;
    }
    getDataIntervally() {
      let data = 'baz';
      setInterval(() => this.defaultCallback(data), 1000);
    }
}

function bar(data) {
  console.log(`<bar> data="${data}"`);
}

const a = new Test();
a.defaultCallback = bar;
a.getDataIntervally();