setInterval in member function of object error - javascript

I'm trying to create a throttling queue of sorts in a nodeJS module. I'm getting this error back:
timers.js:265
callback.apply(this, args);
^
TypeError: Cannot read property 'apply' of undefined
at wrapper [as _onTimeout] (timers.js:265:13)
at Timer.listOnTimeout (timers.js:110:15)
I'm guessing that I'm doing something stupid, as usual, but is there a reason that it loses the closure scope or something when the second interval runs?
var queueSvc = function(settings){
var queue = ['bob', 'is', 'name', 'my', 'hi'];
var svc = {};
var runtime;
svc.addQuery = function(queueEntry){
queue.push(queueEntry);
};
svc.stopQueue = function(){
clearInterval(runtime);
};
svc.startQueue = function(){
runtime = setInterval(runQueue(queue), settings.queueInterval);
};
svc.emptyQueue = function(){
//This method of emptying the array needs to change
//if we decide to make the queue a public property
queue = [];
};
return svc;
};
function runQueue(queue){
console.log(JSON.stringify(queue));
if(queue.length > 0){
var entry = queue.pop();
console.log(entry);
}
}
var it = queueSvc({queueInterval: 3000});
it.startQueue();

This is a very common mistake. You are running runQueue(queue) immediately and then passing the return value of that to setInterval(). That return value is undefined so what you are doing is essentially this:
runQueue(queue);
setInterval(undefined, settings.queueInterval);
This is obviously, not what you want. Whenever you put () after a function as in runQueue() that means to run it immediately. A function name or definition without () after it is just passing a function reference that can be called later.
So, you need to pass a function reference to setInterval() that can be called LATER like this:
setInterval(function() {
runQueue(queue);
}, settings.queueInteval);
Sometimes people understand it a bit better when you break it out into a named function (not necessary, but helpful in understanding what is going on):
function run() {
runQueue(queue);
}
setInterval(run, settings.queueInteval);
Here you see you are passing only a function reference to setInterval() and letting the timer infrastructure call the function some time later.
The anonymous function in my first code block accomplishes the same thing. It declares a second function that we can pass a reference of to setInterval() and when that is called, it then calls runQueue(queue) with the desired argument.

This line looks very suspcious:
setInterval(runQueue(queue), settings.queueInterval);
runQueue doesn't return a function, in fact it returns nothing (undefined). You probably want:
setInterval(function () {
runQueue(queue);
}, settings.queueInterval);

To supplement existing answers, wrapping runQueue into something callable works. However, you could also restructure your logic entirely.
var queueSvc = function(settings){
var queue = ['bob', 'is', 'name', 'my', 'hi'];
var svc = {};
var runtime;
svc.addQuery = function(queueEntry){
queue.push(queueEntry);
};
svc.stopQueue = function(){
clearInterval(runtime);
};
svc.startQueue = function(){
runtime = setInterval(svc.runQueue, settings.queueInterval);
};
svc.emptyQueue = function(){
//This method of emptying the array needs to change
//if we decide to make the queue a public property
queue = [];
};
svc.runQueue = function() {
console.log(JSON.stringify(queue));
if(queue.length > 0){
var entry = queue.pop();
console.log(entry);
}
};
return svc;
};
var it = queueSvc({queueInterval: 3000});
it.startQueue();

This is exactly what I was looking for, thanks.
Only one issue: you implemented a stack, not a queue.
Queues are FIFO and use push() and shift()
Stacks are LIFO and use push() and pop()
As long as the ordering does not matter, then either is fine.

Related

print in console all the function which is being executed in javascript

I am creating AngularJS Javascript application in which i have 500/600 function in a single Directive,
Many functions are Inter connected with each other,
flow starts from the On load Event,
I want to know when i run the project,
which functions are being called on Onload Event
and i want to print the same on console,
I google it but i am not able to get anything,
is there any way to find out the functions which is being executed?
Call console.trace('calling on-load') to find stack-trace on on-load function. It would be better to call trace on the last function you expect to be executed to find all other function which has been called before.
You can wrap all your functions into "log wrapper":
var self = this;
function LogWrapper(action){
return function(){
console.log(action.name);
return action.apply(self, arguments);
}
}
//usage:
function ActualFunctionInner(arg1, arg2){
//some logic
}
var ActualFunction = LogWrapper(ActualFunctionInner);
var result = ActualFunction(1, 2);//console: ActualFunctionInner
Second solution is via Proxy:
let handler = {
get(target, propKey) {
var inner = target[propKey];
return function () {
console.log(inner.name);
return inner.apply(this, arguments);
};
}
};
var loggedSelf = new Proxy(self, handler);
var result = loggedSelf.ActualFunction(1, 2);//console: ActualFunction

How to execute blocks of functions?

This is my code:
var testStacks = new Array();
function test(elem) {
console.log(elem);
... asynch operations
}
testStacks.push(test("hello 0"));
testStacks.push(test("hello 1"));
testStacks.push(test("hello 2"));
testStacks.push(test("hello 3"));
testStacks.push(test("hello 4"));
// init first 3 functions
testStacks[0];
testStacks[1];
testStacks[2];
and I want to execute 3 functions at time. So hello 0, hello 1 and hello 2 start together at the beginning. Than, once one function finish (they do asynch ops) it must calls the next one (not executed yet) from the array. And so on...
Seems that testStacks[0] does nothing, and when I push the function, it will be executed.
How can I do this? (I want to avoid setInterval()).
A simple approach could be pushing both the function AND the parameters.
var testStacks = new Array();
function test(elem) {
console.log(elem);
... asynch operations
}
testStacks.push({func: test, param: "hello 0"});
testStacks.push({func: test, param: "hello 1"});
testStacks.push({func: test, param: "hello 2"});
testStacks.push({func: test, param: "hello 3"});
testStacks.push({func: test, param: "hello 4"});
// init first 3 functions
testStacks[0].func(testStacks[0].param);
testStacks[1].func(testStacks[1].param);
testStacks[2].func(testStacks[2].param);
This could be generalized and cleaned up in many ways, of course, but should give you a basic idea.
You are executing the function and pushing the return value. Push a function instead:
testStacks.push(function(){ test("hello 0"); });
Whatever solution you'll choose, you'll need something like a third party object to manage the current call stack, and a way to notify this object whenever an operation is completed. Regarding the following (pretty dirty) code, I've decided to use a simple callback called from the test function :
var Stack = function (maxCalls, stack) {
this.ongoing = 0;
this.maxCalls = maxCalls;
Array.prototype.push.apply(this, stack);
this.next(); // starts immediately
};
Stack.prototype = Object.create(Array.prototype);
Stack.prototype.next = function () {
var me = this;
while (this.length && this.ongoing < this.maxCalls) {
this.ongoing++;
// calls the next function
// passing a callback as a parameter
this.shift()(function () {
me.ongoing--;
me.next();
});
}
};
See this demo for a use case : http://jsfiddle.net/wared/5eu8b/. As you can see, functions are called one after the other in a First In First Out way, but they complete in any order.
Hope it can help somehow :)

Reassign variables stored in closure using a callback or global function

EDIT
Let me get more to the point. I'm trying to create a psuedo promise implementation. The idea here being that I have a callback that won't be executed until an asynchronous call is received. So I'm simply queueing up all the calls to this function until the time at which it's notified that it can be executed. The queue is emptied and any further call to the function is SUPPOSED to execute immediately, but for some reason, the function is still queueing. This is because, for whatever reason, my redefinition of the runner function is not working correctly. The code below was my sleep deprived, frustrated version of every thought that went through my head. Here's the actual code:
function Promise(callback){
var queue = []
, callback = callback
, runner = function(){
queue.push({
context: this,
args: Array.prototype.slice.call(arguments, 0)
});
}
;//var
runner.exec = function(){
for(var i = 0, ilen = queue.length; i < ilen; i++){
var q = queue[i];
callback.apply(q.context, q.args);
}
runner = callback;
};
return runner;
}
test = Promise(function(){
$('<div/>').appendTo('#output').html(Array.prototype.slice.call(arguments,0).toString());
});
test(1,2);
test(3,4);
test.exec();
test(5,6);​
http://jsfiddle.net/a7gaR/
I'm banging my head against the wall with this one. I'm trying to reassign variables in a function from a call outside the function itself (ideally by passing a reassignment function as a callback). In the example I posted on jsfiddle, I made a global function that, in theory, has a reference to the variables contained within its parent function. Upon calling that external function, I expect it to reassign the values that the other function is using. It doesn't seem to work this way.
window.test = function temp() {
var val = 7,
func = function() {
return val;
};
window.change = function() {
window.test.val = 555555;
$('<div>Changing ' + val + ' to ' + window.test.val +
'</div>').appendTo($output);
val = window.test.val;
temp.val = window.test.val;
func = function() {
return 'Why isn\'t this working?';
}
}
return func();
}
var $output = $('#output');
$('<div/>').appendTo($output).html('::' + test() + '::');
window.change();
$('<div/>').appendTo($output).html('::' + test() + '::');
http://jsfiddle.net/YhyMK/
The second time you call test you're creating a new local variable called func and defining a new window.change that closes over that new variable. The changes you made to the original func by calling the original window.change are not relevant in the second call.
Also note that the following line:
window.test.val = 555555;
...does not modify/refer to the val variable in the outer function. window.test.val refers to a property named val on the test object (which happens to be a function), not any local variable.
You are trying to refer to a local variable in a function with the syntax func.varname. That won't work, that's not the way local variables work.
I finally created a function that would perform this operation. The gist for it is here: https://gist.github.com/2586972.
It works like this...
You make a call to Defer passing the callback whose functionality you'd like to delay:
var deferredCB = Defer(function(){ console.log(this,arguments) };
deferredCB will now store all of the arguments you pass allowing them to be executed at some later date:
defferedCB(1);
defferedCB(2);
Now, when you're ready to perform the operation, you simply "execute" deferredCB:
defferedCB.exec();
Which results in:
// window, 1
// window, 2
All future calls to deferredCB will be executed immediately. And now that I'm thinking about it, I'll probably do a rewrite to allow you to reset deferredCB to it's pre-executed state (storing all the arguments again).
The key to making it work was having a wrapper function. Javascript simply won't let you reassign a function while it's being executed.
TADA!!!

Set event handler on arbitrary JS function?

I'd like to write a Chrome extension that works with a particular JS-based chat application. It needs to be made aware every time the chat receives a message.
Now, I can obviously do this easily by setting up a timer and checking to see if $("chat-messages").childElements().length has increased, but I'd rather go with the more elegant method of setting up an event handler of some sort to fire every time appendChatMessage() is invoked. Is there a way to do this?
var oldfunc = appendChatMessage;
appendChatMessage = function() { eval(oldfunc); myChatMessageReceivedHandler(); }
Doesn't seem to be working.
If there is a method appendChatMessage that is called every time a new message arrives, you could do like this
var old = appendChatMessage;
appendChatMessage = function() {
// call the initial method and store the result
var result = old.apply( this, arguments );
// do your stuff here
// return the initial result
return result;
};
You have to do oldfunc(). Besides that I'd create an event to to that
var oldfunc = appendChatMessage;
appendChatMessage = function() { oldfunc(); $(document).trigger("msg_received"); }
$(document).bind("msg_received", function(params){
//do your logic when message arrives
});
You should decide which element to attach the event into and its params.
Hope this helps. Cheers
var oldfunc = appendChatMessage;
appendChatMessage = function() { eval(oldfunc(); myChatMessageReceivedHandler(); }
Should work, depending on the context.
var f = function () { console.log('foo'); }
var f2 = f;
f = function () { f2(); console.log('bar'); }
This should print:
foo
bar

Is there a way to set a handler function for when a set of events has happened?

eg I have two concurrent AJAX requests, and I need the result from both to compute a third result. I'm using the Prototype library, so it might look something like this:
var r1 = new Ajax.Request(url1, ...);
var r2 = new Ajax.Request(url2, ...);
function on_both_requests_complete(resp1, resp2) {
...
}
One way would be to use polling, but I'm thinking there must be a better way.
Update: An acceptable solution must be free of race conditions.
On the callback function of each request, set a boolean such as
request1Complete and request2Complete
and call on_both_requests_complete(resp1,resp2).
In the handler function, check to see if both booleans are set. If not, just return and fall out of the function. The callback functions should be serialized, in that they cannot happen simultaneously, so this should work. If they could happen in parallel, you would break on a race condition.
This is how I would do it. The approach is a general one, which gives you more flexibility and reuse, and avoids coupling and the use of globals.
var makeEventHandler = function(eventMinimum, callback) {
var data = [];
var eventCount = 0;
var eventIndex = -1;
return function() {
// Create a local copy to avoid issues with closure in the inner-most function
var ei = ++eventIndex;
return function() {
// Convert arguments into an array
data[ei] = Array.prototype.slice.call(arguments);
// If the minimum event count has not be reached, return
if ( ++eventCount < eventMinimum ) {
return;
}
// The minimum event count has been reached, execute the original callback
callback(data);
};
};
};
General usage:
// Make a multiple event handler that will wait for 3 events
var multipleEventHandler = makeMultipleEventHandler(3, function(data) {
// This is the callback that gets called after the third event
console.log(data);
});
multipleEventHandler()(1,2,3);
var t = multipleEventHandler();
setTimeout(function() {t("some string");}, 1000);
multipleEventHandler()({a: 4, b: 5, c: 6});
Output from callback (condensed by Firebug):
[[1, 2, 3], ["some string"], [Object { a=4, more...}]]
Notice that the order of data in the final callback is in order of the calling events, even though the second "event" executes after the third.
To use this in context of your Ajax requests:
var onBothComplete = makeMultipleEventHandler(2, function(data) {
// Do something
...
});
new Ajax.Request(url1, {onComplete: onBothComplete()});
new Ajax.Request(url2, {onComplete: onBothComplete()});
Edit: I've updated the function to force data to always maintain the asynchronously received event data in the synchronously executed order (the previous caveat no longer exists).
Well, you have to remember that the JS implementation in browsers is not really concurrent, and use that to your advantage. So what you would want to do is in each handler check if the other has finished. Example in jQuery:
var other_done = false;
$.get('/one', function() {
if (other_done) both_completed();
other_done = true;
alert('One!');
});
$.get('/two', function() {
if (other_done) both_completed();
other_done = true;
alert('Two!');
});
function both_completed() {
alert('Both!');
}
Based on Justin Johnson's response to this question:
function sync(delays /* Array of Functions */, on_complete /* Function */) {
var complete_count = 0;
var results = new Array(delays.length);
delays.length.times(function (i) {
function on_progress(result) {
results[i] = result;
if (++complete_count == delays.length) {
on_complete(results);
}
}
delays[i](on_progress);
});
}
This assumes each delay accepts one argument: an "on progress" event handler, which takes one argument: the result that the delay is trying to compute. To complete the example in my original question, you'd use it like so:
var delays = [];
delays[0] = function (on_progress) {
new Ajax.Request(url1, {onSuccess: on_progress});
};
delays[1] = function (on_progress) {
new Ajax.Request(url2, {onSuccess: on_progress});
};
function on_complete(results) { alert(results.inspect()); }
sync(delays, on_complete);
The one thing I'm not sure of is whether this avoids a race condition. If the expression ++complete_count == delays.length always happens atomically, then this should work.
You can use the concept where you set temporary variables and wait for the "last" request to go. To do this, you can have the two handle functions set the tmp vars to the return val and then call your "on_both_requests_complete" function.
var processed = false;
var r1 = new Ajax.Request(...);
var r2 = new Ajax.Request(...);
(function() {
var data1;
var data2;
function handle_r1(data) {
data1 = data;
on_both_requests_complete();
};
function handle_r2(data) {
data2 = data;
on_both_requests_complete();
};
function on_both_requests_complete() {
if ( (!data1 || !data2) || processed) {
return;
}
processed = true;
/* do something */
};
}();

Categories