This is probably not possible but maybe some of the stackoverflow geniuses can find a solution :)
W would like to have a function like this:
var myCrazyFunc;
myCrazyFunc = function (param1, callback) {
var funcId;
// I would like to get an Id of the function passed by callback
// which will be different for those two calls in example below
funcId = getFuncId(callback);
callback();
};
myCrazyFunc("param1", function () {
dosomething1;
});
myCrazyFunc("param1", function () {
dosomething2;
});
Please don't ask why I need that :) Simply it would simplify my code if that was possible.
Here is the function I made:
var myCrazyFunc;
var latestID = 0;
var funcToID = {};
function getFuncId(f) {
if (f in funcToID) {
return funcToID[f];
}
funcToID[f] = ++latestID;
return latestID;
}
myCrazyFunc = function(param1, callback) {
var funcId;
// I would like to get an Id of the function passed by callback
// which will be different for those two calls in example below
funcId = getFuncId(callback);
console.log(funcId);
callback();
};
myCrazyFunc("param1", function() {
'a';
});
myCrazyFunc("param1", function() {
'b';
});
this example would log:
1
2
I you run it with the same function code you get the same id, like here:
myCrazyFunc("param1", function() {
'a';
});
myCrazyFunc("param1", function() {
'a';
});
Ouput:
1
2
I hope that's ok.
Related
Hi I'm trying to understand callbacks in javascript and have come across this code here from a tutorial that I'm following:
var EventEmitter = require('events');
var util = require('util');
function Greetr() {
this.greeting = 'Hello world!';
}
util.inherits(Greetr, EventEmitter);
Greetr.prototype.greet = function(data) {
console.log(this.greeting + ': ' + data);
this.emit('greet', data);
}
var greeter1 = new Greetr();
greeter1.on('greet', function(data) {
console.log('Someone greeted!: ' + data);
});
greeter1.greet('Tony');
Now I notice that the greeter1.on function takes a callback with a parameter. However I'm not sure how this is implemented internally. I tried looking through the nodejs event.js file but I'm still confused. I am aware that there are ways around this specific implementation by using an anonymous function wrapping the callback with parameters but I want to understand how to use the same format as above.
tldr: How can I create my own function that takes a callback and a parameter in the same fashion as greeter1.on above.
Thank you
Your function needs to define a new property on the current instance with the callback passed as an argument, so it can be called later, like so:
function YourClass () {
this.on = function(key, callback) {
this[key] = callback;
}
}
// Usage
const instance = new YourClass();
instance.on('eventName', function (arg1, arg2) {
console.log(arg1, arg2);
});
instance.eventName("First argument", "and Second argument")
// logs => First argument and Second argument
Callback is just passing a function as a parameter to another function and that being triggered. You can implement callback fashion as below
function test(message, callback) {
console.log(message);
callback();
}
//Pass function as parameter to another function which will trigger it at the end
test("Hello world", function () {
console.log("Sucessfully triggered callback")
})
class MyOwnEventHandler {
constructor() {
this.events = {};
}
emit(evt, ...params) {
if (!this.events[evt]) {
return;
}
for (let i = 0, l = this.events[evt].length; i < l; i++) {
if (!params) {
this.events[evt][i]();
continue;
}
this.events[evt][i](...params);
}
}
on(evt, eventFunc) {
if (!this.events[evt]) {
this.events[evt] = [];
}
this.events[evt].push(eventFunc);
}
}
var myHandler = new MyOwnEventHandler();
myHandler.on('test', function (...params) {
console.log(...params);
});
myHandler.emit('test', 'Hello', 'World');
I have something similar to this:
function MyObject() {
var self = this;
this.callback = function() {
self.finishParams = Array.prototype.slice.call(arguments);
self.parent.finish();
}
this.start = function() {
this.currentCallback = this.callback
this.startFunc.apply(this.startFunc, this.startParams.concat(this.currentCallback));
}
}
this.startFunc is a function which is something like function(param1, param2, param3, callback)
I have no control over this.startFunc except that it will call the callback with some paramaters.
THE PROBLEM
I have a this.currentCallback because I need to be able to cancel the callback. That is, I've already called this.startFunc and need to prevent the callback.
The problem is, MyObject might send another callback (never 2 at a time) but if I don't cancel the first one immediately when I need to, I won't know which one is valid when I get them back! Might be confusing so here's a diagram:
Send callback 1 off
Need to cancel! Cancel callback A somehow here
Send callback 2 off (still say function has callback 1)
By this point, if I didn't cancel A, then when I got the callback back, I wouldn't know which it was. If I DID cancel A, then I know it's B and no one has to worry.
Please tell me if you do not understand :)
A proof-of-concept of the scheme laid out in the comments: create a new closure for each callback, let callback identify if it is active or not.
function foreignAPIThatStartsACallback(callback) {
setTimeout(callback, 1000);
}
var activeCallback;
function wrapCallback(callback) {
var args = Array.prototype.slice.call(arguments, 1);
var that = this;
var wrappedCallback = function() {
if (wrappedCallback == activeCallback) {
callback.apply(that, args);
}
}
activeCallback = wrappedCallback;
return wrappedCallback;
}
function myCallback(what, who) {
console.log(who + " says " + what);
}
foreignAPIThatStartsACallback(wrapCallback(myCallback, "Hello", "Mario"));
foreignAPIThatStartsACallback(wrapCallback(myCallback, "Goodbye", "Luigi"));
// Mario is cancelled when Luigi gets started
With multiple possible actives:
function foreignAPIThatStartsACallback(callback) {
setTimeout(callback, 1000);
}
var activeCallbacks = {};
function wrapCallback(callback) {
if (!wrapCallback.count) wrapCallback.count = 0;
wrapCallback.count++;
var args = Array.prototype.slice.call(arguments, 1);
var that = this;
var wrappedCallback = function() {
if (wrappedCallback.id in activeCallbacks) {
cancelCallback(wrappedCallback);
callback.apply(that, args);
}
}
wrappedCallback.id = wrapCallback.count;
activeCallbacks[wrapCallback.count] = true;
return wrappedCallback;
}
function cancelCallback(wrappedCallback) {
delete activeCallbacks[wrappedCallback.id];
}
function myCallback(what, who) {
console.log(who + " says " + what);
}
var marioCallback = wrapCallback(myCallback, "Hello", "Mario");
foreignAPIThatStartsACallback(marioCallback);
var luigiCallback = wrapCallback(myCallback, "Goodbye", "Luigi");
foreignAPIThatStartsACallback(luigiCallback);
var daisyCallback = wrapCallback(myCallback, "Mama?", "Peach");
foreignAPIThatStartsACallback(daisyCallback);
cancelCallback(luigiCallback);
// Mario and Daisy go off
I am using the following code below and essentially it takes an element as input (i.e.):
$(#someDiv).Calculator();
but the problem is that I want to call this plugin's function within itself, but I don't know how to get an object/handle to itself to call the function. caching off "this" does not have the proper reference.
(function ($) {
jQuery.fn.Calculator = function () {
var selectedObjects = this;
var control = $(selectedObjects[0])[0];
$("#btnCalculate").click(function(){
// this is where calculate needs to be called
someObject.calculate(...);
});
return {
calculate: function (value) {
// do some code
return selectedObjects;
}
};
}
})(jQuery);
Any ideas/direction would be of great help! Thank you all!
Try
(function ($) {
jQuery.fn.Calculator = function () {
var selectedObjects = this;
var control = $(selectedObjects[0])[0];
$("#btnCalculate").click(function(){
// this is where calculate needs to be called
calculator.calculate(...);
});
var calculator = {
calculate: function (value) {
// do some code
return selectedObjects;
}
};
return calculator;
}
})(jQuery);
I'm trying to apply what I learned about callback functions in this post I made to extend to 3 functions, but am having some trouble getting things working. Can someone please help me understand how I can get these three functions to fire in sequence?
var yourCallback = function(args, second) {
var t = setTimeout(function() {
$('body').append(args);
}, 800);
second('3-');
}
var yourSecondCallback = function(args) {
var t = setTimeout(function() {
$('body').append(args);
}, 800);
}
function function1(args, callback, yourSecondCallback) {
$('body').append(args);
if (callback) {
callback('2-');
}
}
function1('1-' , yourCallback);
http://jsfiddle.net/loren_hibbard/WfKx2/3/
Thank you very much!
You need to nest the callbacks to get them to call in order.
var yourCallback = function(args, second) {
var t = setTimeout(function() {
$('body').append(args);
second('3-');
}, 800);
}
var yourSecondCallback = function(args) {
var t = setTimeout(function() {
$('body').append(args);
}, 800);
}
function function1(args, callback) {
$('body').append(args);
if (callback) {
callback('2-', yourSecondCallback);
}
}
function1('1-' , yourCallback);
Here's your altered fiddle
Your function names confuse me, so I'm just going to make some up to demonstrate a simple approach:
function1('-1', function(){
secondCallback(...);
thirdCallback(...);
...
});
Any reason a simple approach like that won't work for you?
Not sure exactly what you are trying to do here, but when you do this in function1:
callback('2-');
You are calling this method:
var yourCallback = function(args, second)
But you are not providing a value for second, so you get an error.
If your first argument and only is going to be an input for all the callbacks then this code can be used for unlimited arguments
var yourCallback = function(args, second) {
var t = setTimeout(function() {
$('body').append(args + ' first function');
}, 800);
}
var yourSecondCallback = function(args) {
var t = setTimeout(function() {
$('body').append(args + ' second function');
}, 800);
}
function function1(args) {
var callbacks = arguments.length - 1;
for (i = 1; i < arguments.length; i++) {
if (typeof(arguments[i] == 'function')) {
arguments[i](arguments[0]);
}
}
}
function1('1-', yourCallback, yourSecondCallback);
Fiddle - http://jsfiddle.net/8squF/
I have a function, mainMethod, that is calling three callback functions.
mainFunction the first callback function(one) will be called and the first parameter will be passed into it.
one will pass the second parameter into the second callback function (two).
two will pass the third parameter into the last callback function (three).
three will just log the last parameter that was passed into it.
function mainFunction(callback1, callback2, callback3){
var first_parameter = "ONE"
callback1(first_parameter);
}
function one(a){
console.log("one: " + a);
var second_parameter = "TWO"
two(second_parameter);
}
function two(b){
console.log("two: " + b);
var third_parameter = "THREE";
three(third_parameter);
}
function three(c){
console.log("three: " + c);
}
mainFunction(one, two, three);
enter code hereI have the following code
function a(){alert("a");}
I want to create a function b as
function b(){alert("a"); alert("b");}
My approach is something like
var b = a + alert("b");
This is of course not working. But I am wondering if there is some kind of library supporting this.
Edit: Maybe I need to describe my scenario so that its more clear what I want to achieve.
I am using async.js library to handler multiple async calls. My code looks like
var values = {};
...
function all() {
var allDfd = $.Deferred();
async.parallel(
[function (callback) {
remoteCall(function (result) {
values.v1 = result;
callback(null, 'one');
});
},
function (callback) {
remoteCall(function (result) {
values.v2 = result;
callback(null, "two");
});
},
function (callback) {
remoteCall(function (result) {
values.v3 = result;
callback(null, "three");
});
}], function (err, results) {
allDfd.resolve();
});
return allDfd.promise();
}
Clearly there are a lot of repetitive code that bothers me. So my idea is to create a function asyncCall to perform the boilerplate tasks. The idea is
var values = {};
...
function all() {
var allDfd = $.Deferred();
function getAsyncCall (func, innerCallback, callback) {
return function asyncCall(func, innnerCallback, callback){
func(innerCallback + callback(null)); // combine innerCallBack and callback code
}
}
async.parallel(
[getAsyncCall(remoteCall, function(result){values.v1=result;},callback),
getAsyncCall(remoteCall, function(result){values.v2=result;},callback),
getAsyncCall(remoteCall, function(result){values.v3=result;},callback),
], function (err, results) {
allDfd.resolve();
});
return allDfd.promise();
}
The line with the comment is what I am pondering. I am trying to create a new function that combines inner and outer callbacks.
You can do
var b = function() { a(); alert('b'); }
You could write:
var a=function(){alert("a");}
var b=function(){a(); alert("b");}
And to go a little further, you can even write a whole function composition function:
function compose( functions ) {
return function(){
for(var i=0; i!=functions.length; ++i) {
functions[i]();
}
};
}
var c=compose( [a, function(){ alert("b"); }] );
(See it at work at http://jsfiddle.net/xtofl/Pdrge/)