I want to stop this running after 10 seconds - javascript

I tried using setTimeout(clearInterval(MY_INT, 10000) in the function olo() but it ran only once and stopped :/ Where could I put it or should I use for()?
There is no <script src></script> tag because I am using online editor. If you guys know how to make VScode like an online editor please suggest.
*
const btn = document.getElementById('Button');
const target = document.getElementById('here');
btn.addEventListener('click', ()=>{
function olo(){
let loadingImage = document.createTextNode('**');
target.appendChild(loadingImage);
}
const MY_INT = setInterval(olo ,1000)
})
<!DOCTYPE html>
<html>
<head>
<title>Loading...</title>
</head>
<body>
<div>
<button id='Button'>load</button>
<h1 id='here'></h1>
</div>
</body>
</html>

The 10000 argument should be in setTimeouts parameters, but you have it in clearInterval.
You should not place it in the olo function, it should be right after you set the interval.
setTimout expects a callback, you have provided it a function call, change clearInterval(MY_INT) to an anonymous function (or any function, but NOT a function call). e.g. () => clearInterval(MY_INT)
Full cleanup of your code with the fixes above (i tweaked the timings slightly to make it easier to play with):
btn.addEventListener("click", () => {
function olo() {
let loadingImage = document.createTextNode("*");
target.appendChild(loadingImage);
}
const MY_INT = setInterval(olo, 500);
setTimeout(() => clearInterval(MY_INT), 3000);
});
Sandbox with fix

Related

Call worker via postmessage from a class

I am currently learning how to handle with workers. I made a very simple example with a class.
All js files are in the src folder.
//***********index.html**************
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script type="module" src="./src/main.js"></script>
</body>
</html>
//***********main.js**************
import {test} from "./test.js";
new test.DataLoader();
//***********test.js***************
export const test = (() => {
class DataLoader{
constructor(){
this.worker = new Worker('./src/worker.js', {type: 'module'});
this.worker.onmessage = (e) => {
this.result = e.data;
console.log(this.result);
};
}//end constructor
}//end class
return {DataLoader};
})();
//***********worker.js***************
postMessage("kimba");
But if I want to trigger the worker via postMessage, it doesn't work. I'm sure it's not a big thing but i just don't see the error.
//***********test.js***************
export const test = (() => {
class DataLoader{
constructor(){
this.worker = new Worker('./src/worker.js', {type: 'module'});
this.worker.onmessage = (e) => {
this.result = e.data;
console.log(this.result);
};
//this is new, call postMessage method
this.postMessage("kimba");
}//end constructor
//this is new, a postMessage method
postMessage(msg){
this.worker.postMessage(msg);
}
}//end class
return {DataLoader};
})();
//***********worker.js***************
self.onmessage = (msg) => {
self.postMessage(msg);
};
Exactly as above, but this time the worker should not respond immediately when it is created, but should wait for a postMessage from DataLoader. Of course, I would like to use this in a more complex environment, but posting 1000 lines here is clumsy. This simple example sums up my problem. I want to call the worker with postmessage from within DataLoader.
The tip with the self got me thinking. msg.data instead of msg alone in the worker.js and it works. Your tip with the self gave me the feeling that maybe one more prefix or postfix is ​​missing. I messed around with it for hours earlier and it wouldn't want to run and your tip put me on the right track. Thank you.
self.onmessage = (msg) => {
self.postMessage(msg.data);
};

Execute function only once after multiple clicks in a row JavaScript

I have two quantity selector buttons.
After the user clicks in any of these buttons (increasing or decreasing quantity), I need to run a function.
But the user can click several times in a row, and I want to execute the function only once.
Like, wait 1 second after each click to run the function. If within this 1 second the user clicks the button again, reset the timer and wait for another second to run the function. When the user doesn´t click again within 1 second, run the function.
What´s the best way to do that in vanilla javascript?
You just need to start a 1 second timer and reset it whenever the button click happens.
let timer
function handleClick() {
clearTimeout(timer)
timer = setTimeout(doSomething, 1000);
}
function doSomething() {
let div = document.getElementById("list")
let p = document.createElement("p")
p.textContent = "1 second passed without a click"
div.append(p)
}
<!DOCTYPE html>
<html>
<body>
<button onclick="handleClick()">Click me</button>
<div id=list></div>
</body>
</html>
I see two solutions:
If each click triggers some request, then disable button until the request is completed
Use throttling for the function invoke. You can use RxJS's throttle or you can write your own throttle method.
https://medium.com/nerd-for-tech/debouncing-throttling-in-javascript-d36ace200cea
You described a classic debounce technique. Here is an implementation:
Taken from https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_debounce
Another way is to dig into Lodash source codes and copy it from there
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
}
// Avoid costly calculations while the window size is in flux.
jQuery(window).on('resize', debounce(calculateLayout, 150));
Here is a nice article and a playground about it https://css-tricks.com/debouncing-throttling-explained-examples/
You can try this in Vanilla JS :
const btn = document.querySelector('#btn');
const callback = event => {
console.log(event);
clearInterval(interval);
}
let interval;
btn.addEventListener('click', event => {
clearInterval(interval);
interval = setInterval( () => callback(event), 1000);
});
And the HTML :
<html>
<body>
<button id="btn">test</button>
</body>
</html>
That way you can pass the event instance to your callback.

window.speechSynthesis.speak(msg) not working until button click

The brief page below does not work. Specifically, "window.speechSynthesis.speak(msg)" does not work until the button has been pressed. If the button has been pressed then the "Hello" message works. If it has not then any calls to "window.speechSynthesis.speak(msg)" do not produce any audible output.
Suspecting that it has something to do with initialization of speechSynthesis - some things have been tried below to ensure that it is initialized when "Hello" is called. None have worked. Although it seems like it should have. It seems like it is getting properly initialized only if it is called from the button press.
The setup of the SpeechSynthesisUtterance itself is the same whether called from the button or the timeout. That setup works when called by the button. But nowhere else until it has been called by the button.
What is wrong here?
<!DOCTYPE html>
<html>
<head>
<title>Voice Test 3</title>
</head>
<body>
<div id="header">User Interface Terminal</div>
<input type="text" id="control_box"></input><br>
<button id="startButton" onclick="voicemessage('Button');">start</button><br>
<script>
function voicemessage(ttstext) {
var msg = new SpeechSynthesisUtterance(ttstext);
msg.volume = 1;
msg.rate = 0.7;
msg.pitch = 1.3;
window.speechSynthesis.speak(msg);
document.getElementById('control_box').value = ttstext;
}
window.speechSynthesis.onvoiceschanged = function() {
document.getElementById('control_box').value = "tts voices recognized";
window.setTimeout(function() {
voicemessage("Hello");
}, 5000);
};
window.addEventListener('load', function () {
var voices = window.speechSynthesis.getVoices();
})
</script>
</body>
</html>
This may be due to the browser itself...
Recent updates in some browsers (Firefox and Chrome) have policies to prevent audio from being accessed unless some user interaction triggers it (like a button click)...

Can I wait for a child window to load the second page?

There are three accessible pages, http://localhost/parent.html, http://localhost/child1.html and http://localhost/child2.php.
Only parent.html is editable for me, whereas the others are not.
child2.php is accessible only through a POST request from child1.html.
What I want to do is to automate extracting data from every child page.
I'm on parent.html now and will access the other two pages from here using a child window.
However, the code which waits for loading the second page doesn't work.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>parent.html</title>
<script>
function waitForLoading(targetWindow) {
return new Promise((resolve, reject) => {
targetWindow.addEventListener("load", resolve);
});
}
document.addEventListener("DOMContentLoaded", async () => {
const childWindow = open("child1.html", "_blank");
await waitForLoading(childWindow);
// do something with DOM
childWindow.document.querySelector("form[action='child2.php']").submit();
await waitForLoading(childWindow); // getting stuck here
// do something with DOM // so, this line is unreachable
});
</script>
</head>
<body>
<h1>parent.html</h1>
</body>
</html>
My questions are:
Why does the code get stuck?
How do I wait for a child window to load the second page?
If it is impossible, do you know any workarounds to achieve the goal?
Thanks.
Why does the code get stuck?
Even if a child window loads another page, it seems not to run load or DOMContentLoaded for the second time or later.
How do I wait for a child window to load the second page?
Loop and watch the loading state of the page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>parent.html</title>
<script>
function waitFirstPage(targetWindow) {
return new Promise((resolve, reject) => {
targetWindow.addEventListener("load", resolve);
});
}
function movePage(targetWindow, action) {
const originalDocument = targetWindow.document;
action();
return new Promise((resolve, reject) => {
(function loop() {
if (targetWindow.document !== null
&& targetWindow.document !== originalDocument
&& targetWindow.document.readyState === "complete") {
resolve();
}
setTimeout(loop, 100);
})();
});
}
document.addEventListener("DOMContentLoaded", async () => {
const childWindow = open("child1.html", "_blank");
await waitFirstPage(childWindow);
// do something with DOM
await movePage(childWindow, () => {
childWindow.document.querySelector("form[action='child2.html']").submit();
});
// do something with DOM
});
</script>
</head>
<body>
<h1>parent.html</h1>
</body>
</html>
If it is impossible, do you know any workarounds to achieve the goal?
No need for workarounds since it is possible.

Check if an Interval is running and viceversa

So i have a web app with basic authentication.
When im logged in, an Interval is set:
$("#login").click(function(e) {
var interval = setInterval(function(){myFunction();}, 2000); });
Then when im logged out i need to stop the interval:
$("#logout").click(function(e) {
if(typeof interval !== 'undefined') clearInterval(interval); });
But it doesnt work, i think the way to check if an interval exist is wrong...i can set the interval so it is running when im logged in, but i need to stop/clear it when i click on my Logout button and it doesnt...
PS. im using the interval to check "myFunction" automatically every 2 seconds, but maybe there is another way to accomplish this without an interval? thx
Your interval variable needs to be declared at a higher scope where it is available to both functions. As you have it now, it is a local variable that ONLY exists within the particular invocation of your event handler function. So, when the next event handler is called, that previous variable no longer exists. You may also want to protect against successive clicks on login:
var interval;
$("#login").click(function(e) {
if (!interval) {
interval = setInterval(function(){myFunction();}, 2000);
}
});
$("#logout").click(function(e) {
clearInterval(interval);
interval = null;
});
And, you don't need to check to see if interval is undefined. You can just call clearInterval() on it and clearInterval() will protect against any invalid argument you pass it.
Here is a simple example where your interval variable should be in global scope for both click events.
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
function myFunction(){
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
var interval;
$("#start").click(function(){
interval = setInterval(function(){
myFunction();
},2000);
});
$("#stop").click(function(){
clearInterval(interval);
});
});
</script>
</head>
<body>
<p id="demo"></p>
<button id="start">Start</button>
<button id="stop">Stop</button>
</body>
</html>

Categories

Resources