Question

I'm having trouble with designing a class which exposes its actions through callbacks. Yes my approach works for me but also seems too complex.

To illustrate the problem I've drawn the following picture. I hope it is useful for you to understand the class/model.

enter image description here

In my approach, I use some arrays holding user defined callback functions.

....

rocket.prototype.on = function(eventName, userFunction) {
 this.callbacks[eventName].push(userFunction);
}

rocket.prototype.beforeLunch = function(){
 userFunctions = this.callbacks['beforeLunch'] 
 for(var i in userFunctions)
   userFunctions[i](); // calling the user function
}

rocket.prototype.lunch = function() {
  this.beforeLunch();
  ...
}

....

var myRocket = new Rocket();

myRocket.on('beforeLunch', function() {
 // do some work
 console.log('the newspaper guys are taking pictures of the rocket');
});

myRocket.on('beforeLunch', function() {
 // do some work
 console.log('some engineers are making last checks ');
});

I'm wondering what the most used approach is. I guess I could use promises or other libraries to make this implementation more understandable. In this slide using callbacks is considered evil. http://www.slideshare.net/TrevorBurnham/sane-async-patterns

So, should I use a library such as promise or continue and enhance my approach?

Was it helpful?

Solution

var Rocket = function () {

    this.timer = null;
    this.velocity = 200;
    this.heightMoon = 5000;
    this.goingToMoon = true;

    this.rocketStatus = {
        velocity: null,
        height: 0,
        status: null
    };

    this.listener = {
    };
}   

Rocket.prototype.report = function () {
    for (var i in this.rocketStatus) {
        console.log(this.rocketStatus[i]);
    };
};

Rocket.prototype.on = function (name,cb) {

    if (this.listener[name]){
        this.listener[name].push(cb);
    }else{
        this.listener[name] = new Array(cb); 
    }
};

Rocket.prototype.initListener = function (name) {
    if (this.listener[name]) {
        for (var i = 0; i < this.listener[name].length; i++) {
            this.listener[name][i]();
        }
        return true;
    }else{

        return false;
    };
}

Rocket.prototype.launch = function () {

    this.initListener("beforeLaunch");

    this.rocketStatus.status = "Launching";
    this.move();

    this.initListener("afterLaunch");
}

Rocket.prototype.move = function () {

    var that = this;

    that.initListener("beforeMove");

    if (that.goingToMoon) {
        that.rocketStatus.height += that.velocity;
    }else{
        that.rocketStatus.height -= that.velocity;
    };

    that.rocketStatus.velocity = that.velocity;

    if (that.velocity != 0) {
        that.rocketStatus.status = "moving";
    }else{
        that.rocketStatus.status = "not moving";
    };

    if (that.velocity >= 600){
        that.crash();
        return;
    }
    if (that.rocketStatus.height == 2000 && that.goingToMoon)
        that.leaveModules();


    if (that.rocketStatus.height == that.heightMoon)
        that.landToMoon();


    if (that.rocketStatus.height == 0 && !that.goingToMoon){
        that.landToEarth();
        return;
    }
    that.report();



    that.initListener("afterMove");

    that.timer = setTimeout(function () {
        that.move();
    },1000)
}


Rocket.prototype.stop = function () {

    clearTimeout(this.timer);
    this.initListener("beforeStop");
    this.velocity = 0;
    this.rocketStatus.status = "Stopped";
    console.log(this.rocketStatus.status)

    this.initListener("afterStop");
    return true;
}

Rocket.prototype.crash = function () {

    this.initListener("beforeCrash");

    this.rocketStatus.status = "Crashed!";
    this.report();
    this.stop();
    this.initListener("afterCrash");
}



Rocket.prototype.leaveModules = function () {

    this.initListener("beforeModules");

    this.rocketStatus.status = "Leaving Modules";

    this.initListener("afterModules");
}

Rocket.prototype.landToMoon = function () {

    this.initListener("beforeLandToMoon");

    this.rocketStatus.status = "Landing to Moon";
    this.goingToMoon = false;

    this.initListener("afterLandToMoon");
}

Rocket.prototype.landToEarth = function () {

    this.initListener("beforeLandToEarth");

    this.stop();
    this.rocketStatus.status = "Landing to Earth";

    this.initListener("afterLandToEarth");
}

Rocket.prototype.relaunch = function () {

    this.initListener("beforeRelaunch");

    this.timer = null;
    this.velocity = 200;
    this.heightMoon = 5000;
    this.goingToMoon = true;

    this.rocketStatus = {
        velocity: 200,
        height: 0,
        status: "relaunch"
    };

    this.launch();

    this.initListener("afterRelaunch");
}

init;

var rocket = new Rocket();

rocket.on("afterLaunch", function () {console.log("launch1")})
rocket.on("afterLandToMoon", function () {console.log("land1")})
rocket.on("beforeLandToEarth", function () {console.log("land2")})
rocket.on("afterMove", function () {console.log("move1")})
rocket.on("beforeLaunch", function () {console.log("launch2")})

rocket.launch();

You can add any function before or after any event.

This is my solution for this kinda problem. I am not using any special methods anything. I was just wonder is there any good practise for this like problems. I dig some promise,deferred but i just can't able to to this. Any ideas ?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top