I thought an interval just delayed the function, but as it turns out it actually loops.
When I include some function that stops the interval after the deletor function ends it doesn't trigger that and I still get Test logged to the console.
document.addEventListener("DOMContentLoaded", function(event) {
let fullURL = window.location.href;
//let fullURL2 = window.location.host + window.location.pathname;
if (fullURL === "https://net.adjara.com/" ||
fullURL === "https://net.adjara.com/Home") {
var timer = setInterval(deletor, 5);
function deletor() {
timer;
var slider = document.querySelector("#slider-con");
var bannerTop = document.querySelector("#MainContent > div:nth-child(2)")
var bannerMiddle = document.querySelector("#MainContent > iframe");
var bannerRandom = document.querySelector("#MainContent > div:nth-child(3)");
if (slider) {
slider.parentNode.removeChild(slider);
}
if (bannerTop) {
bannerTop.parentNode.removeChild(bannerTop);
}
if (bannerMiddle) {
bannerMiddle.parentNode.removeChild(bannerMiddle);
}
if (bannerRandom) {
bannerRandom.parentNode.removeChild(bannerRandom);
}
function stopInterval() {
clearInterval(timer);
}
console.log("Test");
/*if ()
clearInterval(timer);*/
};
} else {
return false;
}
});
What you're looking for is setTimeout. It runs only once.
setTimeout(deletor, 5);
Also, you don't need to write timer variable inside of your closure like you would in Python. Javascript captures everything that's inside of lexical scope.
The code you provided works ¯\_(ツ)_/¯
Maybe the problem is coming from what triggers stopInterval()
But as mentioned in comments / other answers, you might be better off with another method
I wouldn't recommend using setTimeout in your case, because it looks like you are simply waiting for some DOM elements to be loaded. The problem with the timeout is that you can't know for sure how fast is the computer that will run your code. Maybe a bad quality phone with an outdated software that will need way more time to run your code than when you test on your personal computer, and that will not have the elements loaded by the time your function will be executed.
jQuery
For this reason, and since you tagged your question with jQuery I think you could use $(elementYouWaitForTheDOM2beLoaded).ready(function2execute) for each element you are watching instead of a having a loop that waits for the elements to be loaded (documentation for "ready" function)
Vanilla JS
And if you want to do it in pure JS it would be document.querySelector(elementYouWaitForTheDOM2beLoaded).on('load', function2execute))
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've written some code in JS that's basically supposed to work like a CSS media query and start this slideshow when the viewport width threshold has been crossed. I know it works because it runs when I call the function in the console, but I cannot figure out why it won't just run on it's own as intended.
I'm guessing I've either done something wrong with the responsive part or there's a super basic error somewhere that I've yet to learn.
So far I've tried "window.InnerWidth", I've tried "screen.width" "document.body.clientWidth" and "window.matchMedia" (and to be honest, I would love to know more about each because I'm fairly new to JS).
Here's the snippet:
function resetCards() {
card.forEach(elem => elem.classList.remove("show"));
}
function showCards(index) {
resetCards();
card[index].classList.add("show");
}
function cardSlide() {
var i = 1;
function loop() {
setTimeout(function() {
showCards(i);
i++;
if (i < card.length) {
loop();
} else if (i == card.length) {
i = 0;
loop();
}
}, 4000);
}
loop();
}
function runShow() {
var i = window.matchMedia("(max-width: 1024px)");
if (i.matches) {
cardSlide();
} else {
console.log("Error!");
}
}
runShow();
Your code only checks once. But the good news is that matchMedia returns an object that as a change event you can hook into that gets triggered whenever the result of the media query changes:
function runShow(e) {
if (e.matches) {
cardSlide();
}
}
window.matchMedia("(max-width: 1024px)").onchange = runShow;
If you want it to run once right away, you need to do that proactively:
function runShow(e) {
if (e.matches) {
cardSlide();
}
}
var match = window.matchMedia("(max-width: 1024px)");
match.onchange = runShow;
runShow(match);
Live Example
That example doesn't do anything when the query goes from matching to non-matching. You might want to do something in an else or similar.
The reason it won't check the width after a certain time is because you are using the setTimeout function, this will only run once. If you want it to check multiple times you should use the setInterval function.
You however want to avoid this as it is not accurate / efficient. you could use eventlisteners instead!
Like one of the answers here stated, you are able to use the onchange event of the window.matchMedia object.
I have a script that changes some values and clicks some buttons in a browser. I'm looking for a way to pause the execution of the code for x seconds without making the browser lag out. I'm using Firefox and I paste this script into its console. I'm aware of the setTimeout() function. However, this function doesn't stop executing the code, but rather waits x seconds till executing it. I'm looking for a complete solution that's similar to Python's time.sleep() function and pauses the execution of the code completely.
var init = 0.01
var start = init
var $odds = $("#oddsOverUnder")
var $button = $("#roll")
var $bet = $("#bet")
function roll(){
$bet.val(start)
$button.click()
//i want to pause the execution of the code here//
$button.click()
//and here//
refreshIntervalId=setInterval(roll2, 2000)}
function roll2(){
var tr = document.querySelector("#myBetsTable tr:nth-child(2)")
var cls = tr.getAttribute('class')
if (cls === 'success'){
start = init
$bet.val(start)}
else{
start = start * 2
$bet.val(start)
$odds.click()}
clearInterval(refreshIntervalId)
roll()}
roll()
There's no equivalent to Python's time.sleep() in JavaScript, which generally executes asynchronously by design. If you'd like to delay execution of code, you can use setTimeout, as you mentioned.
Without understanding exactly what your code is supposed to do, I can't suggest the ideal architecture for this problem. There's definitely a better way to do it than what I'm about to suggest. Still, to answer your question, you can simulate what you're asking this way:
function roll() {
$bet.val(start);
$button.click();
setTimeout(function () {
$button.click();
setTimeout(function () {
refreshIntervalId = setInterval(roll2, 2000);
}, 1000);
}, 1000);
}
How about setting timeouts inside a timeout?
function roll() {
$bet.val(start)
$button.click()
setTimeout(function() {
$button.click();
setTimeout(
function() {
$button.click();
refreshIntervalId = setInterval(roll2, 2000)
},
5000
);
},
5000
);
}
also, please see: https://stackoverflow.com/a/951057/2119863
I would like to animate an html page with something like this:
function showElements(a) {
for (i=1; i<=a; i++) {
var img = document.getElementById(getImageId(i));
img.style.visibility = 'visible';
pause(500);
}
}
function pause(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}
Unfortunately, the page only renders once javascript completes.
If I add
window.location.reload();
after each pause(500); invocation, this seems to force my javascript to exit. (At least, I do not reach the next line of code in my javascript.)
If I insert
var answer=prompt("hello");
after each pause(500), this does exactly what I want (i.e. update of the page) except for the fact that I don't want an annoying prompt because I don't actually need any user input.
So... is there something I can invoke after my pause that forces a refresh of the page, does not request any input from the user, and allows my script to continue?
While the javascript thread is running, the rendering thread will not update the page. You need to use setTimeout.
Rather than creating a second function, or exposing i to external code, you can implement this using an inner function with a closure on a and i:
function showElements(a) {
var i = 1;
function showNext() {
var img = document.getElementById(getImageId(i));
img.style.visibility = 'visible';
i++;
if(i <= a) setTimeout(showNext, 500);
}
showNext();
}
If I add window.location.reload(); after each pause(500) invocation, this seems to force my javascript to exit
window.reload() makes the browser discard the current page and reload it from the server, hence your javascript stopping.
If I insert var answer=prompt("hello"); after each pause(500), this does exactly what I want.
prompt, alert, and confirm are pretty much the only things that can actually pause the javascript thread. In some browsers, even these still block the UI thread.
Your pause() function sleeps on the UI thread and freezes the browser.
This is your problem.
Instead, you need to call setTimeout to call a function later.
Javascript is inherently event-driven/non-blocking (this is one of the great things about javascript/Node.js). Trying to circumvent a built in feature is never a good idea. In order to do what you want, you need to schedule your events. One way to do this is to use setTimeout and simple recursion.
function showElements(a) {
showElement(1,a);
}
function showElement(i, max) {
var img = document.getElementById(getImageId(i));
img.style.visibility = 'visible';
if (i < max) {
setTimeout(function() { showElement(i+1, max) }, 500);
}
}
var i = 1;
function showElements(a) {
var img = document.getElementById(getImageId(i));
img.style.visibility = 'visible';
if (i < a) {
setTimeout(function() { showElements(a) }, 500);
}
i++;
}
showElements(5);
function showElements(a,t) {
for (var i=1; i<=a; i++) {
(function(a,b){setTimeout(function(){
document.getElementById(getImageId(a)).style.visibility = 'visible'},a*b);}
)(i,t)
}
}
The t-argument is the delay, e.g. 500
Demo: http://jsfiddle.net/doktormolle/nLrps/
I am trying to create the following functionality in my javascript:
$("mySelector").each(function(){
// Do something (e.g. change div class attribute)
// call to MyFunction(), the iteration will stop here as long as it will take for myFunction to complete
});
function myFunction()
{
// Do something for e.g. 5 seconds
}
My question is how can I stop every iteration for the duration of the myFunction()?
No, that isnt possible. You'll have to code it differently, possibly with a setTimeout based on the current index of .each.
$("mySelector").each(function(i){
// Do something (e.g. change div class attribute)
// call to MyFunction(), the iteration will stop here as long as it will take for myFunction to complete
setTimeout(myFunction,i*5000);
});
function myFunction()
{
// Do something for e.g. 5 seconds
}
Edit: You can also do it with queuing: http://jsfiddle.net/9Bm9p/6/
$(document).ready(function () {
var divs = $(".test");
var queue = $("<div />");
divs.each(function(){
var _this = this;
queue.queue(function(next) {
myFunction.call(_this,next);
});
});
});
function myFunction(next) {
// do stuff
$(this).doSomething();
// simulate asynchronous event
var self = this;
setTimeout(function(){
console.log(self.id);
// go to next item in the queue
next();
},2000);
}
Here's a jsFiddle that I think will do what you need:
http://jsfiddle.net/9Bm9p/2/
You would just need to replace the selector with what you use.
The "loop" that is occurring will wait for myFunction to finish before moving on to the next element. I added the setTimeout inside of myFunction to simulate it taking a period of time. If you are using asynchronous things, such as an AJAX request, you would need to put the call to myFunction inside of the complete method...or in the callback of an animation.
But as someone already commented, if everything in myFunction is synchronous, you should be able to use it as you are. If you are looking for this process to be asynchronous, or if things in myFunction are asynchronous, you cannot use a for loop or .each().
(function () {
"use strict";
var step = 0;
var content = $("mySelector");
var max = content.length;
var speed = 5000; // ms
var handle = setInterval(function () {
step++;
if (step >= max) {
clearInterval(handle);
} else {
var item = content[step];
// do something
}
}, speed);
}());
setInterval will do it once-every-n-miliseconds, and clearInterval will stop it when you're done. This won't lock up the browser (provided your "do something" also doesn't). FRAGILE: it assumes that the results of $("mySelector") are valid for the duration of the task. If that isn't the case then inside do something then validate item again.