简体   繁体   中英

JS - Calling class methods inside of callback function

I'm currently having a problem and don't know how to solve it correctly.

I'm developing a web application with js using the WebMidi API.

I want to load all midi devices into a dropdown after WebMidi is loaded. As far as I understood it I have to pass the enable function of Webmidi a callback function:

WebMidi.enable(function (err) {
  if (err) {
    console.log("WebMidi could not be enabled.", err);
  } else {
    console.log("WebMidi enabled!");
  }
});

The problem I am having is I cannot reference class methods inside the callback function, but I have to call the method that's fills the dropdown list with all midi inputs, as soon as WebMidi is enabled.

My code looks like this:

class MidiListener{
    constructor(){
        this.enable();
        this.fillDropdown(Webmidi.inputs);
    }


    enable(){
        WebMidi.enable(function (err) {
            //Enable WebMidi
            if (err) {
              console.log("WebMidi could not be enabled.", err);
              window.alert("WebMidi is not supported by your Browser.")
            } 
            else {
                console.log("WebMidi enabled!");
            } 
        });
    }
...

The problem is fillDropdown() is called before WebMidi finished activating, and the array is empty at the time. Can I somehow reference class methods inside the callback function?

WebMidi.enable is an asynchronous function , meaning it allows you to specify what to do once WebMidi is enabled. The problem is that you're not using this functionality to full power.

Imagine you're the guy who shoots the gun to start a race: your code is the equivalent of shooting and turning your eyes away from the race but still wanting to know when the race ends. If you want to do something right after the race ends, better look at the race, right?

Right now, the constructor function starts the WebMidi.enable race and immediately tries to fill the dropdown. That's not what you want - you want to fill the dropdown when the race ends.

To resolve your problem, make MidiListener.enable take a callback function that gets executed when WebMidi.enable is done without errors. This will allow you to do something right when WebMidi.enable finishes.

class MidiListener {
    constructor() {
        this.enable(() => {
            this.fillDropdown(WebMidi.inputs);
        });
    }

    enabledTest(err) {
        if(err) console.log("F");
        else console.log("Yeeee");
    }

    enable(callback) {
        WebMidi.enable(function (err) {
            //Enable WebMidi
            if (err) {
                // An error occured while starting WebMidi
                console.log("WebMidi could not be enabled.", err);
                window.alert("WebMidi is not supported by your Browser.")
            } 
            else {
                // WebMidi enabled successfully
                callback();
            } 
        });
    }

Now, this.fillDropdown will be executed only after WebMidi starts successfully. With the above analogy, the constructor function now says "fill the dropdowns when the WebMidi.enable race ends".

Also, note that I used an arrow function to create the callback function . This is important because the this keyword, when used with regular function -keyword functions, acts like a special keyword. What this refers to depends on where it's called - which in your case is somewhere in WebMidi 's code.

To avoid that, use an arrow function which treats this like a regular variable with regular scoping rules. There are other workarounds too - this answer explains things very well .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM