I have this following piece of code:
var stats = {
....,
checkExistance :
function(url){
var newUrl = url.substring(0, url.lastIndexOf("/")) + "/asyncCheckChartExistance";
var xhrObj = stats.getXhr();
var poolInterval = setInterval("poll()", 100);
function poll(){
xhrObj.open("GET", newUrl, true);
xhrObj.send(null);
xhrObj.onreadystatechange = function(){
if(xhrObj.readyState === 4 && xhrObj.status === 200){
if (xhrObj.responseText.length === true){
console.log("Exists!");
clearInterval(poolInterval);
} else {
console.log("Not Yet!");
}
}
}
}
},
}
I created the stats namespace. In this namespace I'm trying to create a function which polls the server every second. I should access this function this way: stats.checkExistance(myUrl).
However it seems that the setInterval function is not able to see the poll() function. I know that this is normal behavior taking in consideration that these are nested inside another function.
If I were to write this in the Global namespace there would be no problem but I'm interested to make this work in this kind of namespace. Any ideas? Thanks!
when you pass a string to setInterval, it runs in the global scope, by default, where poll would not be defined since it only exists in the scope of the checkExistance function.
To fix the issue, pass an anonymous function to setInterval instead:
var poolInterval = setInterval(function () {
poll();
}, 100);
Passing an anonymous function is usually the best idea as it allows you to write any javascript expressions/statements for the interval instead of just calling one function.
When you pass a string to setInterval, that string is interpreted as global code, and since poll is not a global function, a reference error is thrown.
However, you can pass a function reference instead of a string, and since the poll function is available in the scope in which the setInterval invocation is made, you can just write this:
var poolInterval = setInterval( poll, 100 );
var stat = {
say: function(name){
function doit(){
console.log(name);
}
setInterval(doit, 1000);
}
};
stat.say("hi");
A simple demo to show how. You will see "hi" every second.
Related
I am using an already defined function and now want to add a pollServer function to it so that this functions runs over and over. I keep getting errors when I try to wrap the existing function in another. Is there a better way to do this?
function callD(id) {
jQuery('document').ready(function pollServer(){
window.setTimeout(function () {
var ab = document.getElementById('a')
console.log(ab);
var bod = document.getElementById(+id)
if (ab == null) {
bod.style.background='green'
} else {
bod.style.background='blue'
}
}, 1200);
})
}
callD();
pollServer();
pollServer isn't defined where you're calling it. Also id isn't being passed to callD, and you also have a +id which doesn't make sense in a document.getElementByid, since if there's any non-number in the ID, that would be NaN. You're also not polling a server, you're setting a timeout once and doing some work that doesn't involve a server. You would want setInterval for regular polling, or to call the function again on some condition like a failure.
$(document).ready(function () {
var intervalId;
function callD(id) {
function pollServer() {
intervalId = window.setInterval(function () {
var ab = document.getElementById('a')
console.log(ab);
var bod = document.getElementById(id)
if (ab == null) {
bod.style.background='green'
} else {
bod.style.background='blue'
}
}, 1200);
}
pollServer();
}
callD('some-id');
// on some condtion eventually:
clearInterval(intervalId);
})
Yeah, jQuery can make things pretty gnarly with all the nested callbacks. To make the code cleaner and easier to understand, I like to split my functions up and define them all at the top-most level of the script, then compose them together like so:
/**
* this function will check for the existing elements
* and update styles
*/
function setBodyStyle(id) {
var ab = document.getElementById('a');
console.log(ab);
var bod = document.getElementById(+id);
if (ab == null) {
bod.style.background='green';
} else {
bod.style.background='blue';
}
}
/**
* this function will create a timeout or interval
* which will in turn run setBodyStyle()
*/
function pollServer() {
// I think you want setInterval here if you're polling?
// setInterval will run _every_ 1200ms,
// setTimeout only runs once after 1200ms
window.setInterval(function() {
// not sure where you're getting id from,
// but you'll want to pass it here
setBodyStyle();
}, 1200);
}
// when the document is ready, run pollServer()
jQuery(document).ready(pollServer);
Having small functions that do one thing is just best-practice for the reasons I mentioned above. This will help your script be more understandable, which will help you find bugs.
For example, two things I don't understand about your code above:
where does the id variable come from? I don't see you passing it to your function from anywhere
how does your script poll the server? I don't see the code for that anywhere either.
Seemed you mean run the function pollServer every 1.2 sec. If so, you'd need to do two things
Use setInterval rather than setTimeout
Delete the last line for the pollServer function, because it is not accessible from outside the ready function block.
I need to clear an interval from another function
window.onload = function(){
var interval = null;
interval = setInterval(function(){
myFunction();
}, 1000);
function stop(){
clearInterval(interval);
}
}
without pass the interval variable
stop();
But I cannot make it working: when I call stop(); the interval continues...
How can I do?
There is an unexpected window.stop function which preexists yours.
That's another proof that global variables/functions are evil.
It might be this function which gets invoked instead of yours, depending on when the script is loaded.
Try to put your function in an object to protect namespaces:
It works in the StackOverflow fiddle:
var i = 0;
function myFunction() {
i++;
console.log(i);
}
var interval = null;
interval = setInterval(function() {
myFunction();
}, 1000);
var myObject = {
stop: function() {
console.log("stopping");
clearInterval(interval);
}
};
<button onclick="myObject.stop();">stop</button>
In the faulty jsFiddle, you get things in iframes, meaning window element is not the same. That's why your function is not invoked. That gives you that kind of errors:
You can put your script in the html to get it working:
jsfiddle
You could simply put something like var interval = null; at the beginning of the JavaScript outside of a function.
It's all about variable scope. A variable defined inside of a function is only available within that function. A variable defined outside of a function or object will be available globally to all functions.
What is the scope of variables in JavaScript?
I found also this solution working:
stop = function(){
clearInterval(interval);
}
The presumption on the answer you've checked as solution is wrong.
Your stop function wouldn't be working regardless of the fact that there are browsers supporting load stop command programmatically.
This [stop] command is a window property and can be deleted and\or be overwritten by a simple variable declaration or by a function with the same name anywhere on the script.
The reason you are not being able to call the stop function ( from the outside ), is because it's a closure.
Regards.
p.s.:
throwing it up on global scope will make it work, visit you fiddle
var i=0;
function myFunction(){
i++;
$('i').html(i);
}
interval = null;
interval = setInterval(function(){
myFunction();
}, 100);
stop = function(){
clearInterval(interval);
}
Preety straight forward question, though I can't find the answer anywhere
I tried these two ways:
setInterval(function(){object/*or this*/.method()},500)
and
setInterval('object/*or this*/.method()',500)
setInterval in fact expects a method as the first argument, though there is an alternative syntax where the first argument can be a string of code (not recommended by most)
If you're having issues with that code, it may have to do with the scope of 'this'
setInterval(function(){this.method()},500)
In the above code, 'this' will refer to the closure itself, and wouldn't be the same as 'this.method' occurring outside of that closure. For example, the following would work:
function MyClass() {
this.thingy = 'yep this is a thingy'
}
var myClass = new MyClass()
// Will log 'MyClass yep this is a thingy'
setInterval(function() { console.log('MyClass', myClass.thingy) }, 1000)
Whereas the following will not work (presuming instantiating the object and calling foo()):
function MyOtherClass() {
this.thingy = 'also a thingy'
}
// Will log 'MyOtherClass undefined'
MyOtherClass.prototype.foo = function() {
setInterval(function() { console.log('MyOtherClass', this.thingy) }, 1000)
}
The second example will work if we get around using 'this' within the closure (presuming instantiating the object and calling bar()):
MyOtherClass.prototype.bar = function() {
var that = this
setInterval(function() { console.log('MyOtherClass', that.thingy) }, 1000)
}
Also be sure that setInterval is being passed the name of a function:
setInterval(someFunction, 500)
rather than executing a function as an argument
setInterval(someFunction(), 500)
This last line of code is usually a mistake, unless someFunction() returns a function itself ;)
The difference between your 2 ways for passing a function to setInterval is whether you want to pass your function as refrence of just copy of it. Allow me to explain it by example:
-1 Referring(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(function () {
obj.testMethod()
}, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
when you run this code, the result 'll be execution of the modified version of testMethod. Because here you dont copy the function! Instead, you refer to it. So whenever function implementation is changed, the last modified version is executed.
-2 Copying(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(obj.testMethod, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
Here all you do is you are passing a copy of the last defined version of the function testMethod to setInterval. So whatever changes you do to testMethod, the result of setInterval will not be changed.
var sc = new stuCore();
function stuCore() {
this.readyPages = [];
this.once = true;
var self = this;
// gets called asynchronously
this.doPrepPage = function (page){
if(self.once == true){
// still gets executed every time, assignment fails
self.once = false;
doSomeStuffOnce();
}
};
this.addReadyPage = function (pageid) {
console.log("readypage called");
this.readyPages.push(pageid);
if (!$.inArray(pageid, self.readyPages) != -1) {
this.doPrepPage(pageid);
}
};
}
why does this assignment fail? I thought I knew the basics of js, but I'm stumped by this. And furthermore what would be a possible solution? call a constructor first and set the variable there?
EDIT:
gets called like this in some other script:
sc.addReadyPage(self.id);
The jQuery.inArray function will return the index in the containing array for the given value. Your script pushes pageid into this.readyPages before checking whether it exists in self.readyPages. this.readyPages and self.readyPages are the same array reference, so the result will always be zero or greater, so the condition that calls doPrepPage will never run.
You could try switching their order around:
this.addReadyPage = function (pageid) {
console.log("readypage called");
if ($.inArray(pageid, self.readyPages) != -1) {
this.readyPages.push(pageid);
this.doPrepPage(pageid);
}
};
(edit: Removed the additional !, thanks #chumkiu)
If I understand correctly you're calling this.doPrepPage as <insert variable name here>.doPrepPage?
If this is the case then your var self passes through to the anonymous function and is stored there, so everytime you call this.doPrepPage it takes the local variable of self.
Try setting self to a global variable, this way it will permanently modify self so each time this.doPrepPage is called it uses the updated variable.
I am having a problem where I want to stop a particular function from executing. This function is located on another plugin which I can't change the core files so I am wondering if I can stop a specific function from that file from executing?
So for example that function is testFunction(); and I want to stop that later in the code maybe in on document ready...etc.
Thanks!
Is the function public (as opposed to private via a closure)? And, does it need to be operational at all for things to work, or can you chop it out in total and be fine? If the latter, you can replace the function with a new one:
otherLibrary.testFunction = function(){};
If you want to disable it for a temporary amount of time, you can store the function in a temporary variable, and restore it later:
var removedFunc = otherLibrary.testFunction;
otherLibrary.testFunction = function(){};
// do something, time passes, whatever...
otherLibrary.testFunction = removedFunc;
Or, if you want to be able to toggle it, a slight variation:
var removedFunc = otherLibrary.testFunction;
var testFunctionEnabled = true;
otherLibrary.textFunction = function(){
if(testFunctionEnabled){
removedFunc.call(this, arguments);
}
};
And then just set testFunctionEnabled as you need to.
you should try to extend the function before you call it e.g.
$.extend(plugin.function, myNewFunction);
also, check the plugin API to see if you can pass a paramter to override the function or actually access the api of the plugin e.g.
$('#mytip').api('hover', myHoverFunction);
If you have access to the object which refers to the "testFunction" function then you could replace it with an empty function, e.g.:
SomePlugin.testFunction = function() { };
Ultimately, if you don't have a way to overwrite that symbol then there's not much you can do to stop the method from running (unless you can provide more details).
If that function schedules itself with setInterval, you can use clearInterval(thefunction) to prevent it from being called again. But if it's a loop, I don't know if that's possible.
Simply set the function to null.
JavaScript example:
function write() {
el.innerHTML += 'Lorem ipsum dolor sit amet.<br />';
if (execute != null) execute();
}
function execute() {
setTimeout(function() { write() }, 500);
}
function abort() {
execute = null;
}
window.onload = function() {
el = document.getElementById('blah');
execute();
}
HTML:
<button type="button" onclick="abort()">Abort</button>
<p id="blah"></p>
Also you can change the following to implement stop/start. For this, assign the execute function to a variable so that you can later assign that variable back to execute.
var oldfunc = execute;
function abort() {
if (execute == null) {
execute = oldfunc;
execute();
} else {
execute = null;
}
alert(execute);//shows the function code
}
You can overwite any method you have access to- but if the code in your module calls it internally you better give it an appropriate return.
document.write=function(){return true};
alert(document.write('tell me more!'))