Javascript callback managment - javascript

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.
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?

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 ?

Related

How to disable method call if instance of object doesn't exist (javascript)

Is there a way to not call a method from the function object (instance of it) if that instance doesn't exist?
This is my function for sticky sidebar and it has 2 methods;
init() and updateSticky();
function stickySideBar(element, options = {}) {
var _this = this;
_this.init = function () {}
_this.updateSticky = function (timeout) {
//this is actually just a debouncer that calls init method
}
}
I want to use this updateSticky on window resize
$(window).on("resize", function () {
newsletterBlog.updateSticky();
sideBarBlog.updateSticky();
if ($(productsSticky.element).length > 0) {
productsSticky.updateSticky();
}
});
now I use if loop to check if an element exists but I would like to do that inside of the instance of that function
if i dont have if loop i get "Uncaught TypeError: e.updateSticky is not a function".
cheers
EDIT
here is the function
function stickySideBar(element, options = {}) {
var _this = this;
console.log("_this :>> ", _this);
//declared element
_this.debouncer;
_this.element = element;
if ($(_this.element).length === 0) {
return;
}
// declared options
_this.parentElementClass = options.parentElementClass;
_this.wrapClass = options.wrapClass;
_this.activeStickyClass = options.activeStickyClass;
_this.top = options.top;
_this.width = options.width;
_this.activeBottomClass = options.activeBottomClass;
_this.disableOnMobile = options.disableOnMobile ? options.disableOnMobile : true;
_this.breakpoint = 992;
_this.init = function () {
};
_this.updateSticky = function (timeout) {
if ($(_this.element).length === 0) return;
var timeoutVal = timeout ? timeout : 100;
clearTimeout(_this.debouncer);
_this.debouncer = setTimeout(function () {
_this.init();
}, timeoutVal);
};
return _this.init();
}

Javascript promise - replace arrow functions

Since the support for arrow functions in JS is still quite low, I'd like to replace them from the following code snippet:
Promise.all([f1(), f2()])
.then(values => { f3(values); })
.catch(values => { f4(values); });
Any idea how can this be achieved?
Should be straight forward, just type "function" instead
Promise.all([f1(), f2()]).then(function(values) {
f3(values);
}).catch(function(values) {
f4(values);
});
Why are you using function expressions at all in there? Do you want to avoid the return values? If not, just go for
Promise.all([f1(), f2()]).then(f3).catch(f4);
This is a solution I wrote to allow existing promise-based code work on promise-less browsers like IE11. Not perfect, but works well.
CanPromise = !!window.Promise;
PromiseResolve = [];
PromiseReject = [];
if (!CanPromise)
{
window.Promise = function (f)
{
var p = {};
p.resolve = function (result)
{
PromiseResolve.push(result);
}
p.reject = function (result)
{
PromiseReject.push(result);
}
return f(p.resolve, p.reject);
};
}
//...........
PromiseResolve.length = 0;
PromiseReject.length = 0;
F1(args);
F2(args);
var AjaxTimeout = 10000;
var period = 100;
var cnt = 0;
var cntMax = parseInt(AjaxTimeout / period);
var t = setInterval(function ()
{
if (PromiseReject.length > 0)
{
clearInterval(t);
Error(PromiseReject[0]);
}
else if (PromiseResolve.length >= 2)
{
clearInterval(t);
Success(PromiseResolve);
}
else if (cnt >= cntMax)
{
clearInterval(t);
}
cnt++;
}, period);

JavaScript's setTimeout doesn't work

I have a simple JS object which emulates traffic lights:
function TrafficLight(redTime, yellowTime, greenTime) {
var self = this;
this.__timer = null;
this.__state = null;
this.__redTime = redTime;
this.__yellowTime = yellowTime;
this.__greenTime = greenTime;
var setnewtimer = function (delay, func) {
console.log('SET!');
if (self.__timer) {
clearTimeout(this.__timer);
}
self.__timer = setTimeout(delay, func);
};
TrafficLight.prototype.toRed = function () {
this.__state = 'red';
setnewtimer(this.__redTime, function () {
console.log('RED!');
self.toGreen();
});
};
TrafficLight.prototype.toGreen = function () {
this.__state = 'green';
setnewtimer(this.__greenTime, function () {
console.log('GREEN');
self.toYellow();
});
};
TrafficLight.prototype.toYellow = function () {
this.__state = 'yellow';
setnewtimer(this.__yellowTime, function () {
console.log('YELLOW');
self.toRed();
});
};
TrafficLight.prototype.state = function () {
return this.__state;
};
this.toGreen();
}
But when I make a TrafficLight object (like var a = new TrafficLight(1000, 1000, 1000);), every a.state() call returns green (so traffic light doesn't change its state by timer. What's wrong with my code?
You don't call setTimeout correctly.
Change
setTimeout(delay, func);
to
setTimeout(func, delay);

Accessing a function within a function from outside in javascript

I have a nested function that I want to call from outside.
var _Config = "";
var tourvar;
function runtour() {
if (_Config.length != 0) {
tourvar = $(function () {
var config = _Config,
autoplay = false,
showtime,
step = 0,
total_steps = config.length;
showControls();
$('#activatetour').live('click', startTour);
function startTour() {
}
function showTooltip() {
}
});
}
}
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
I was hoping to call it by tourvar.showTooltip(); but I seem to be wrong :) How can I make showTooltip() available from outside the function?
since my previous answer was really a hot headed one, I decided to delete it and provide you with another one:
var _Config = "";
var tourvar;
// Module pattern
(function() {
// private variables
var _config, autoplay, showtime, step, total_steps;
var startTour = function() { };
var showTooltip = function() { };
// Tour object constructor
function Tour(config) {
_config = config;
autoplay = false;
step = 0;
total_steps = _config.length;
// Provide the user with the object methods
this.startTour = startTour;
this.showTooltip = showTooltip;
}
// now you create your tour
if (_Config.length != 0) {
tourvar = new Tour(_Config);
}
})();
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
function outerFunction() {
window.mynestedfunction = function() {
}
}
mynestedfunction();

how to clear all javascript Timeouts?

i have a loop function that in first 5 seconds it runs social1() and in second 5 seconds it runs social2() then loop ...
i have 2 hover functions too
i need clear all active timeouts because when i hover on images (.social1 & .social2), i can see that multiple timeouts are running
how to fix this?
function social1() {
$('.social1').fadeTo(500, 1);
$('.social2').fadeTo(500, 0.5);
timeout = setTimeout(function() {
social2();
}, 5000);
}
function social2() {
$('.social1').fadeTo(500, 0.5);
$('.social2').fadeTo(500, 1);
timeout = setTimeout(function() {
social1();
}, 5000);
}
$(document).ready(function ()
{
social1();
$('.social1').hover(
function () {
window.clearTimeout(timeout);
social1();
},
function () {
timeout = setTimeout(function() {
social2();
}, 5000);
}
);
$('.social2').hover(
function () {
window.clearTimeout(timeout);
social2();
},
function () {
timeout = setTimeout(function() {
social1();
}, 5000);
}
);
__EDIT__
To manage a collection of timeouts (and intervals), you could use following snippet.
This will allow to clear any timeouts or intervals set anywhere in code, although, you have to set this snippet before setting any timeout or interval. Basically, before processing any javascript code or external script which uses timeout/interval.
JS:
;(function () {
window.timeouts = {},
window.intervals = {},
window.osetTimeout = window.setTimeout,
window.osetInterval = window.setInterval,
window.oclearTimeout = window.clearTimeout,
window.oclearInterval = window.clearInterval,
window.setTimeout = function () {
var args = _parseArgs('timeouts', arguments),
timeout = window.osetTimeout.apply(this, args.args);
window.timeouts[args.ns].push(timeout);
return timeout;
},
window.setInterval = function () {
var args = _parseArgs('intervals', arguments),
interval = window.osetInterval.apply(this, args.args);
window.intervals[args.ns].push(interval);
return interval;
},
window.clearTimeout = function () {
_removeTimer('timeouts', arguments);
},
window.clearInterval = function () {
_removeTimer('intervals', arguments);
},
window.clearAllTimeout = function () {
_clearAllTimer('timeouts', arguments[0]);
},
window.clearAllInterval = function () {
_clearAllTimer('intervals', arguments[0]);
};
function _parseArgs(type, args) {
var ns = typeof args[0] === "function" ? "no_ns" : args[0];
if (ns !== "no_ns")[].splice.call(args, 0, 1);
if (!window[type][ns]) window[type][ns] = [];
return {
ns: ns,
args: args
};
}
function _removeTimer(type, args) {
var fnToCall = type === "timeouts" ? "oclearTimeout" : "oclearInterval",
timerId = args[0];
window[fnToCall].apply(this, args);
for (var k in window[type]) {
for (var i = 0, z = window[type][k].length; i < z; i++) {
if (window[type][k][i] === timerId) {
window[type][k].splice(i, 1);
if (!window[type][k].length) delete window[type][k];
return;
}
}
}
}
function _clearAllTimer(type, ns) {
var timersToClear = ns ? window[type][ns] : (function () {
var timers = [];
for (var k in window[type]) {
timers = timers.concat(window[type][k]);
}
return timers;
}());
for (var i = 0, z = timersToClear.length; i < z; i++) {
_removeTimer(type, [timersToClear[i]]);
}
}
}());
How to use it:
Set timeout(s)/interval(s) as usual:
var test1 = setTimeout(function(){/**/, 1000);
var test2 = setTimeout(function(){/**/, 1000);
Then you could use to clear both:
clearAllTimeout(); // clearAllInterval(); for intervals
This will clear both timeouts (test1 & test2)
You can use some namespaces to clear only specific timers, e.g:
// first (optional) parameter for setTimeout/setInterval is namespace
var test1 = setTimeout('myNamespace', function(){/**/, 1000); // 'myNamespace' is current namespace used for test1 timeout
var test2 = setTimeout(function(){/**/, 1000); // no namespace used for test2 timeout
Again, clearAllTimeout(); will clear both timeouts. To clear only namespaced one, you can use:
clearAllTimeout('myNamespace'); // clearAllInterval('myNamespace'); for namespaced intervals
This will clear only test1 timeout
You could for some reason wish to delete non namespaced timeouts only. You could then use:
clearAllTimeout('no_ns'); // clearAllInterval('no_ns'); for non namespaced intervals only
This will clear only test2 timeout in this example
See jsFiddle DEMO
__END of EDIT__
Old post specific to opening question here:
You could try that:
var timeouts = [];
timeouts.push(setTimeout(function() {
social2();
}, 5000));
timeouts.push(setTimeout(function() {
social1();
}, 5000));
//etc...
function clearAllTimeouts(){
for(var i = 0, z = timeouts.length; i < z; i++)
clearTimeout(timeouts[i]);
timeouts = [];
}
UPDATED following David Thomas comment
var timeouts = {'social' : [], 'antisocial' : []};
//a social timeout
timeouts.social.push(setTimeout(function() {
social1();
}, 5000));
//an anti-social timeout
timeouts.antisocial.push(setTimeout(function() {
antisocial1();
}, 5000));
function clearTimeouts(namespace){
for(var i = 0, z = timeouts[namespace].length; i < z; i++)
clearTimeout(timeouts[namespace][i]);
timeouts[namespace] = [];
}
//usage e.g
clearTimeouts("social");
//Incase if you are looking for full fledged code
var dict = {};
function checkForIntervals(id){
var index = index;
var result = findOrAddProperty(id);
if(result.length != 0){
clearTimeoutsFor(id);
}
dict[id].push(setTimeout(function(){alertFunc(id,index);}, 60000));
};
// to clear specific area timeout
function clearTimeoutsFor(namespace){
for(var i = 0, z = dict[namespace].length; i < z; i++)
clearTimeout(dict[namespace][i]);
dict[namespace] = [];
}
to clear all timeouts
function clearAllTimeOuts(){
for (key in dict) {
for(var i = 0, z = dict[key].length; i < z; i++)
clearTimeout(dict[key][i]);
dict[key] =[];
}
};
function findOrAddProperty(str){
var temp = [];
for (key in dict) {
if(key == str){
if (dict.hasOwnProperty(key)) {
temp = dict[key];
break;
}
}
}
if(temp.length == 0){
dict[str] = [];
}
return temp;
};
function alertFunc(id,index) {
jQuery(document).ready(function($) {
do the ajax call here after 1 min
});
};

Categories

Resources