How can user break JS loop with a button - javascript

How a user can stop a loop by clicking a button
Here what I need to do in my loop :
HTML :
<input type="button" id="stop" value="Stop" />
<input type="button" id="go" value="Go" />
<div id="div"> </div>
Javascript :
document.getElementById('go').addEventListener('click', function(){
// request to server that return a list of object.
// for each returned objet, I do another request to the server. like that
for(let i=0; i < objets.length; i++){
// request to the server.
// update the div for progress bar like 1%..2%
}
});
document.getElementById('stop').addEventListener('click', function(){
// how to break the loop made by go button
});

If you're running a simple for (..) loop, this cannot be stopped via external influence. Everything is happening on the same thread in Javascript, unless your code "ends" at some point and returns control to the browser for a while no UI interaction can happen. The easiest way to have a "loop" is via a setTimeout or setInterval:
interval = null;
startBTN.onclick = function () {
var i = 0;
interval = setInterval(function () {
console.log(i++); // this is inside your loop
}, 1);
};
stopBTN.onclick = function () {
clearInterval(interval);
};

Related

JavaScript Async\Await understanding [duplicate]

I have a web page where a javascript calculation in a function takes lot of time to finish and makes the page to freeze. What technique should I use to make sure the javascript does not freeze the browser when the calculation is happening in the background?
If you only need to do a calculation and don't need to access the DOM during the long running calculation, then you have two options:
You can break the calculation up into pieces and do a piece at a time on a setTimeout(). On each setTimeout() call, the browser will be free to serve other events and will keep the page alive and responive. When you finish the last piece of the calculation, you can then carry out the result.
You can run the calculation in the background using a webworker in modern browsers. When the calcuation is done in the webworker, it sends a message back to the main thread and you can then update the DOM with the result.
Here's a related answer that also shows an example: Best way to iterate over an array without blocking the UI
Let me elaborate on #jfriend00's answer by giving a concrete stripped down example. Here is a long-running JavaScript process that can be started by clicking a button. Once it runs, it freezes the browser. The process consists of a long loop that repeats some workload where one iteration takes comparatively little time.
Due to the browser freeze, debugging a script like this is not easy. One alternative to avoid browser freeze is using a web worker. The drawback of that approach is the poor debuggabilty of web workers per se: Tools like Firebug are not supported.
<html>
<head>
<script>
var Process = function(start) {
this.start = start;
}
Process.prototype.run = function(stop) {
// Long-running loop
for (var i = this.start; i < stop; i++) {
// Inside the loop there is some workload which
// is the code that is to be debugged
console.log(i);
}
}
var p = new Process(100);
window.onload = function() {
document.getElementById("start").onclick = function() {
p.run(1000000000);
}
}
</script>
</head>
<body>
<input id="start" type="button" value="Start" />
</body>
</html>
Using a Queue data structure (e.g. http://code.stephenmorley.org/javascript/queues/), an interval timer and some small modification to the control flow of the original process one can build a GUI that doesn't freeze the browser, leaves the process fully debuggable and even allows additional features
like stepping, pausing and stopping.
Here is how it goes:
<html>
<head>
<script src="http://code.stephenmorley.org/javascript/queues/Queue.js"></script>
<script>
// The GUI controlling process execution
var Gui = function(start) {
this.timer = null; // timer to check for inputs and/or commands for the process
this.carryOn = false; // used to start/pause/stop process execution
this.cmdQueue = new Queue(); // data structure that holds the commands
this.p = null; // process instance
this.start = start;
this.i = start; // input to the modified process
}
Gui.prototype = {
/**
* Receives a command and initiates the corresponding action
*/
executeCmd: function(cmd) {
switch (cmd.action) {
case "initialize":
this.p = new Process(this);
break;
case "process":
this.p.run(cmd.i);
break;
}
},
/*
* Places next command into the command queue
*/
nextInput: function() {
this.cmdQueue.enqueue({
action: "process",
i: this.i++
});
}
}
// The modified loop-like process
var Process = function(gui) {
this.gui = gui;
}
Process.prototype.run = function(i) {
// The workload from the original process above
console.log(i);
// The loop itself is controlled by the GUI
if (this.gui.carryOn) {
this.gui.nextInput();
}
}
// Event handlers for GUI interaction
window.onload = function() {
var gui = new Gui(100);
document.getElementById("init").onclick = function() {
gui.cmdQueue.enqueue({ // first command will instantiate the process
action: "initialize"
});
// Periodically check the command queue for commands
gui.timer = setInterval(function() {
if (gui.cmdQueue.peek() !== undefined) {
gui.executeCmd(gui.cmdQueue.dequeue());
}
}, 4);
}
document.getElementById("step").onclick = function() {
gui.carryOn = false; // execute just one step
gui.nextInput();
}
document.getElementById("run").onclick = function() {
gui.carryOn = true; // (restart) and execute until further notice
gui.nextInput();
}
document.getElementById("pause").onclick = function() {
gui.carryOn = false; // pause execution
}
document.getElementById("stop").onclick = function() {
gui.carryOn = false; // stop execution and clean up
gui.i = gui.start;
clearInterval(gui.timer)
while (gui.cmdQueue.peek()) {
gui.cmdQueue.dequeue();
}
}
}
</script>
</head>
<body>
<input id="init" type="button" value="Init" />
<input id="step" type="button" value="Step" />
<input id="run" type="button" value="Run" />
<input id="pause" type="button" value="Pause" />
<input id="stop" type="button" value="Stop" />
</body>
</html>
While this approach certainly doesn't fit all long-running scripts one can think of, it certainly
can be adapted to any loop-like scenario. I'm using it to port Numenta's HTM/CLA artificial
intelligence algorithms to the browser.
Some browsers have only one thread for running your code and updating the UI (in other words, until the calculation is complete, the browser will appear "frozen"). You'll want to try to perform the action asynchronously, in one way or another.
If the calculation is really expensive, you might want to make a call to the server and let the server do the calculation, and callback the client when the calculation is done.
If the calculation is kind of expensive, you can try to do it in chunks on the client. This isn't actually asynchronous (as the client will block while executing each chunk) but the goal is to make the chunks small enough that the blocking is not noticeable.
setTimeout(function() { ..code }, 0);
I recommend this for heavy execution time, and also for on load ajax you could try to add
$(window).on("load", function (e) { }); // for jquery v3
if its in the loading process.
I think this should resolve your problem,
function myClickOperation(){
var btn_savebutton2 = document.querySelector("input[id*='savebutton2']");
setTimeout(function () { btn_savebutton2.click() }, 1000);
}
// Full Html content
<html>
<script>
function myClickOperation(){
var btn_savebutton2 = document.querySelector("input[id*='savebutton2']");
document.getElementById('savebutton1').disabled = true;
setTimeout(function () { btn_savebutton2.click() }, 1000);
}
function testClick(){
var idd = document.getElementById("myid");
idd.innerHTML =idd.innerHTML +"<br/>" + new Date();
if(true){
setTimeout(function () { testClick() }, 1);
}
}
</script>
<body>
<input type="button" id="savebutton1" onclick="myClickOperation()" value="Click me" />
<input type="button" id="savebutton2" onclick="testClick()" value="Do not click this" />
<input type="text"/>
<input type="button" value="temp"/>
<div style="height: 300px;overflow-y: scroll;" id="myid"/>
</body>

Javascript redirect/logout after inactivity (with modal popup)

The following JS does not redirect or logout automatically, it only redirects to the url when clicking 'OK' on the modal.
// reset main timer i,e idle time to 0 on mouse move, keypress or reload
window.onload = reset_main_timer;
document.onmousemove = reset_main_timer;
document.onkeypress = reset_main_timer;
document.onscroll = reset_main_timer;
// create main_timer and sub_timer variable with 0 value, we will assign them setInterval object
var main_timer = 0;
var sub_timer = 0;
// this will ensure that timer will start only when user is loged in
var user_loged_in = $("#user_loged_in").val()
// within dilog_set_interval function we have created object of setInterval and assigned it to main_timer.
// within this we have again created an object of setInterval and assigned it to sub_timer. for the main_timer
// value is set to 15000000 i,e 25 minute.note that if subtimer repeat itself after 5 minute we set user_activity
// flag to inactive
function dialog_set_interval(){
main_timer = setInterval(function(){
if(user_loged_in == "true"){
$("#inactivity_warning").modal("show");
sub_timer = setInterval(function(){
$("#user_activity").val("inactive")
},3000);
}
},10000);
}
// maintimer is set to 0 by calling the clearInterval function. note that clearInterval function takes
// setInterval object as argument, which it then set to 0
function reset_main_timer(){
clearInterval(main_timer);
dialog_set_interval();
}
// logout user if user_activity flag set to inactive, when he click ok on popup. whenuser click O.K
// on the warning the subtimer is reset to 0
$(".inactivity_ok").click(function(){
clearInterval(sub_timer);
if($("#user_activity").val() == "inactive"){
window.location = window.location // if your application not manage session expire
//automatically. clear cookies and session her
}
});
<div id="inactivity_warning" class="modal hide fade" data-backdrop="static" style="top:30%">
<div class="modal-header">
<button type="button" class="close inactivity_ok" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<div class="row-fluid">
<div id="custom_alert_message" class="span12">
You will be logged out in due to inactivity very shortly.
</div>
</div>
<div class="modal-footer">
O.K
</div>
</div>
</div>
<input id="user_activity" name="user_activity" type="hidden" value="active" />
<input id="user_loged_in" name="user_loged_in" type="hidden" value="true" />
I would like the modal to appear as a warning message to the user.. letting them know that they will be logged out shorlty... they can click to remain on the page or ignore and it will automatically redirect to the logout page.
Edit
Now you have everything together except the css... Do not start making webapp by the design, nobody prefer a pretty non-working app.
I've used jQuery since you seems to use it yourself.
userIsLogguedIn is not implemented since I have no clue about your way to authenticate user.
logout must also be defined correctly.
There is no Ok keep me connected since every mouse event will set the current activity and hide the modal.
$( document ).ready( initApp);
function initApp(){
console.debug('initApp');
const activityModal = $('#modal');
activityModal.hide();
const activityMaxDelayWarning = 5 * 1000;
const activityMaxDelay = 35 * 1000;
const activityCheckInterval = 5 * 1000;
activityRegister();
document.addEventListener('mousemove', activityRegister);
setInterval( activityCheck, activityCheckInterval);
function activityRegister() {
popupHide();
activityLast = Date.now();
console.debug('Activity set to', activityLast);
}
function userIsLogguedIn() {
//DO it
return true;
}
function activityCheck() {
const delay = Date.now() - activityLast;
console.debug("Activity delay is", delay);
if ( !userIsLogguedIn() ) {
console.debug(" user is not logged in");
return;
}
if ( delay > activityMaxDelay ) {
console.debug(" will logout");
logout();
} else if ( delay > activityMaxDelayWarning ) {
console.debug(" will show warning");
popupShow();
}
}
function popupShow(){
activityModal.show();
}
function popupHide(){
activityModal.hide();
}
function logout() {
window.location.href='https://stackoverflow.com/questions/65007832/javascript-redirect-logout-after-inactivity-with-modal-popup/65008157';
}
}
<html>
<head>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
</head>
<body>
<div id="modal">
<p>You will be logged out in due to inactivity very shortly.</p>
</div>
<div>After some time, a warning message will appears ahead</div>
</body>
</html>

disabling a button while running a function

I have a function in Javascript which is called by clicking a button and it takes approximately one minute to be finished. How can I disable the button after one click and enable it again after function is finished?
I need this process to prevent spamming.
I tried the following piece of code, but it is not working. It is still possible to click the button several times.
Javascript:
function myFunc()
{
document.getElementById("Btn").disabled = true;
\\do something for one minute
document.getElementById("Btn").disabled = false;
}
html:
<button type="button" id="Btn" onclick="myFunc()">Generate!</button>
Your code is working fine. Maybe your function runs quickly that's why it appears as you can spam.
If you're calling function thru ajax, make sure async is false (default is true)
function myFunc() {
document.getElementById("Btn").disabled = true;
setTimeout(function() {
console.log('hey');
document.getElementById("Btn").disabled = false;
}, 1000);
}
<button type="button" id="Btn" onclick="myFunc()">Generate!</button>

Add pause function to soundjs

I have tried using:
createjs.Sound.pause;
mySound.stop();
Nothing works. Right now it have a stop button but if the stop button is pressed then the sound would not be played again.
This is the soundjs that im using. soundjs
My code is exactly the same with the source code of it. Thanks for any help!
I end up doing it like this Based on Stephen Lightcap answer:
Javascript inside the head tag:
function load() {
// Update the UI
document.getElementById("display").innerText = ".";
// Load the sound
createjs.Sound.alternateExtensions = ["mp3"];
createjs.Sound.addEventListener("fileload", handleFileLoad);
createjs.Sound.registerSound({id:"mySound", src:"../../test.mp3"});
}
function handleFileLoad(event) {
// Update the UI
document.getElementById("display").innerHTML = ".";
document.getElementById("stopBtn").disabled = "";
// Play the loaded sound
createjs.Sound.play(event.src,{loop:2});
}
var instance = createjs.Sound.play(event.src);
</script>
Button inside the body tag:
<input id="pausBtn" type="button" value="Pause" onclick="pause()"/>
Javascript for the button onclick. Placed below the button. :
<script>
function pause(){
instance.pause();
}
</script>
But I got an error saying :
Uncaught TypeError: Cannot read property 'pause' of undefined
at pause (phkk.html:560)
at HTMLInputElement.onclick (phkk.html:177)
You can store it in an var and then use the function pause()
var instance = createjs.Sound.play(event.src);
Have button that calls a method that will store the pause
<input id="pausBtn" type="button" value="Pause" onclick="pause()"/>
The JS function:
function pause(){
instance.pause();
}
EDIT
I went over the docs and it appears it doesn't function like that any more, so you're going to have to use the paused property
Here's a rough outline on how it works for me:
<script>
var instance;
function load() {
// Update the UI
document.getElementById("display").innerText = ".";
// Load the sound
createjs.Sound.alternateExtensions = ["mp3"];
createjs.Sound.addEventListener("fileload", handleFileLoad);
createjs.Sound.registerSound({id:"mySound", src:"../../test.mp3"});
}
function handleFileLoad(event) {
// Update the UI
document.getElementById("display").innerHTML = ".";
document.getElementById("stopBtn").disabled = "";
// Play the loaded sound
instance = createjs.Sound.play(event.src,{loop:2});
}
function pause(){
instance.paused ? instance.paused = false : instance.paused = true;
}
</script>
The HTML buttons:
<body>
<input id="loadBtn" type="button" value="Begin Loading" onclick="load()"/>
<input id="stopBtn" type="button" value="Stop Playing" onclick="createjs.Sound.stop();" disabled="disabled" />
<input id="pauseBtn" type="button" value="Pause" onclick="pause()"/>
<label id="display">Waiting for User Input. Click "Begin Loading".</label>

Debugging long running scripts that freeze the browser [duplicate]

This question already has answers here:
How to avoid freezing the browser when doing long-running computations in Javascript
(5 answers)
Closed 7 years ago.
Let's say I have a long-running JavaScript process that can be started by clicking a
button. Once it runs, it freezes the browser. The process consists of a long loop
that repeats some workload where one iteration takes comparatively little time. Here is
a stripped down version of such a 'loop-like' process:
<html>
<head>
<script>
var Process = function(start) {
this.start = start;
}
Process.prototype.run = function(stop) {
// Long-running loop
for (var i = this.start; i < stop; i++) {
// Inside the loop there is some workload which
// is the code that is to be debugged
console.log(i);
}
}
var p = new Process(100);
window.onload = function() {
document.getElementById("start").onclick = function() {
p.run(1000000000);
}
}
</script>
</head>
<body>
<input id="start" type="button" value="Start" />
</body>
</html>
Due to the browser freeze, debugging a loop-like script is not easy. One alternative to avoid browser freeze is using a web worker. The drawback of that approach is the poor debuggabilty of web workers: Tools like Firebug are not supported.
Is there a way to avoid browser freeze while maintaining debuggabilty? If yes, the script could be debugged until it is stable and delegated to a web worker for production.
It turns out there is a way to achieve this. Using a Queue data structure
(e.g. http://code.stephenmorley.org/javascript/queues/), an interval timer and some small
modification to the control flow of the original process one can build a GUI that doesn't
freeze the browser, leaves the process fully debuggable and even allows additional features
like stepping, pausing and stopping.
Here is how it goes:
<html>
<head>
<script src="http://code.stephenmorley.org/javascript/queues/Queue.js"></script>
<script>
// The GUI controlling process execution
var Gui = function(start) {
this.timer = null; // timer to check for inputs and/or commands for the process
this.carryOn = false; // used to start/pause/stop process execution
this.cmdQueue = new Queue(); // data structure that holds the commands
this.p = null; // process instance
this.start = start;
this.i = start; // input to the modified process
}
Gui.prototype = {
/**
* Receives a command and initiates the corresponding action
*/
executeCmd: function(cmd) {
switch (cmd.action) {
case "initialize":
this.p = new Process(this);
break;
case "process":
this.p.run(cmd.i);
break;
}
},
/*
* Places next command into the command queue
*/
nextInput: function() {
this.cmdQueue.enqueue({
action: "process",
i: this.i++
});
}
}
// The modified loop-like process
var Process = function(gui) {
this.gui = gui;
}
Process.prototype.run = function(i) {
// The workload from the original process above
console.log(i);
// The loop itself is controlled by the GUI
if (this.gui.carryOn) {
this.gui.nextInput();
}
}
// Event handlers for GUI interaction
window.onload = function() {
var gui = new Gui(100);
document.getElementById("init").onclick = function() {
gui.cmdQueue.enqueue({ // first command will instantiate the process
action: "initialize"
});
// Periodically check the command queue for commands
gui.timer = setInterval(function() {
if (gui.cmdQueue.peek() !== undefined) {
gui.executeCmd(gui.cmdQueue.dequeue());
}
}, 4);
}
document.getElementById("step").onclick = function() {
gui.carryOn = false; // execute just one step
gui.nextInput();
}
document.getElementById("run").onclick = function() {
gui.carryOn = true; // (restart) and execute until further notice
gui.nextInput();
}
document.getElementById("pause").onclick = function() {
gui.carryOn = false; // pause execution
}
document.getElementById("stop").onclick = function() {
gui.carryOn = false; // stop execution and clean up
gui.i = gui.start;
clearInterval(gui.timer)
while (gui.cmdQueue.peek()) {
gui.cmdQueue.dequeue();
}
}
}
</script>
</head>
<body>
<input id="init" type="button" value="Init" />
<input id="step" type="button" value="Step" />
<input id="run" type="button" value="Run" />
<input id="pause" type="button" value="Pause" />
<input id="stop" type="button" value="Stop" />
</body>
</html>
While this approach certainly doesn't fit all long-running scripts one can think of, it certainly
can be adapted to any loop-like scenario. I'm using it to port Numenta's HTM/CLA artificial
intelligence algorithms to the browser.

Categories

Resources