How to safely send message to a running function in javascript - javascript

I tried to work this code:
var foo=0
window.onmouseup=function(){
foo=1
}
window.onmousedown=function(){
while(foo==0);
console.log("bar")
}
the "bar" is not shown and the browser (I use Edge) stuck there(unable to close the page), I had to use Ctrl+T and then Ctrl+W
I guess the problem is foo==0 is optimized, so it reads from the cache, but I don't know how to avoid it. Or are there other methods?

You could use setInterval() and put the if statement and the rest of the code in there:
var foo = 0
window.onmouseup = function() {
foo = 1
}
window.onmousedown = function() {
var interval = setInterval(() => {
if (foo !== 0) {
clearInterval(interval);
console.log("bar")
}
});
}

Actually, I think the problem is that your while loop will just continue running until it "breaks", or ends the loop. However, foo will always be 1 and never 0 after mouseup, therefore the program gets stuck in the while loop forever, and no other tasks on the browser including the important ones get run.
TL:DR program stuck on while

Related

how to "kill" or cancel setTimeout function

How can I "kill" this setTimout function but not to break my code?
I tried with clear and it didn't work.
For some reason when I delete it everywhere it breaks my code (also if i remove this function evertwhere).
When I say "return" on the top before timeout executes my jQuery shows up but my code doesn't work.
To mention also my jQuery file loads in Mozilla. It also loads on my local machine in Chrome and Safari, but not in live on the server( im also using Wordpress) Safari/Chrome.
Function with the setTimeout
function queueRender() {
var _this = this;
settings.queueRenderTimeout = setTimeout(function(){
render();
}, settings.debounce);
if(typeof settings.queueRenderTimeout !== "undefined") {
clearTimeout(settings.queueRenderTimeout)
}
render();
}
Here is render function
function render() {
element.find(">").remove();
var t = templates.quiz(quiz);
element.append(t);
$(settings.append).append(element);
}
-- so in this case, my jQuery loads, but my quiz breaks.
if i change the order and put first IF statement then my code doesnt break.
Here is my settings:
var defaults = {
append: "body",
quiz_template: "#quiz_template",
question_template: "#question_template",
answer_template: "#answer_template",
result_template: "#result_template",
shuffle: true
// debounce: 10
}
Code is something working sometimes don't. It works on my local machine, but not on the server. I feel like there is still some delay from the setTimout even when I leave it "undefined".

Chrome-extension:Can the script run separately even when the page is not active? [duplicate]

When events are queued with setTimeout/setInterval, and the user is viewing a separate tab, Chrome and Firefox enforce a minimum 1000ms lag before the event is executed. This article details the behaviour.
This has been discussed on StackOverflow previously, but the questions and answers only applied to animations. Obviously, an animation can just be forced to update to the latest state when a user re-enters the tab.
But the solution does not work for sequenced audio. I have Web Audio API playing several audio files in sequence, and setTimeout is used to countdown to when the next audio file plays. If you put the tab in the background, you get an annoying 1 second gap between each pattern -- an extreme flaw in an API designed for advanced audio.
You can witness this behaviour in various HTML5 sequencers, e.g. with PatternSketch -- just by entering a pattern, playing, and going to another tab.
So I'm in need of a workaround: a way to queue events without the 1000ms clamp. Does anyone know of a way?
The only solution I can think of is to have window.postMessage run every single millisecond and check each time if the event is to execute. That is definitely detrimental to performance. Is this the only option?
Apparently there is no event system planned for Web Audio API, so that is out of question.
EDIT: Another answer is to use WebWorkers per https://stackoverflow.com/a/12522580/1481489 - this answer is a little specific, so here's something more generic:
interval.js
var intervalId = null;
onmessage = function(event) {
if ( event.data.start ) {
intervalId = setInterval(function(){
postMessage('interval.start');
},event.data.ms||0);
}
if ( event.data.stop && intervalId !== null ) {
clearInterval(intervalId);
}
};
and your main program:
var stuff = { // your custom class or object or whatever...
first: Date.now(),
last: Date.now(),
callback: function callback() {
var cur = Date.now();
document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
this.last = cur;
}
};
var doWork = new Worker('interval.js');
doWork.onmessage = function(event) {
if ( event.data === 'interval.start' ) {
stuff.callback(); // queue your custom methods in here or whatever
}
};
doWork.postMessage({start:true,ms:250}); // tell the worker to start up with 250ms intervals
// doWork.postMessage({stop:true}); // or tell it just to stop.
Totally ugly, but you could open up a child popup window. However, all this does is transfer some of the caveats to the child window, i.e. if child window is minimized the 1000ms problem appears, but if it is simply out of focus, there isn't an issue. Then again, if it is closed, then it stops, but all the user has to do is click the start button again.
So, I suppose this doesn't really solve your problem... but here's a rough draft:
var mainIntervalMs = 250;
var stuff = { // your custom class or object or whatever...
first: Date.now(),
last: Date.now(),
callback: function callback(){
var cur = Date.now();
document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
this.last = cur;
}
};
function openerCallbackHandler() {
stuff.callback(); // queue your custom methods in here or whatever
}
function openerTick(childIntervalMs) { // this isn't actually used in this window, but makes it easier to embed the code in the child window
setInterval(function() {
window.opener.openerCallbackHandler();
},childIntervalMs);
}
// build the popup that will handle the interval
function buildIntervalWindow() {
var controlWindow = window.open('about:blank','controlWindow','width=10,height=10');
var script = controlWindow.document.createElement('script');
script.type = 'text/javascript';
script.textContent = '('+openerTick+')('+mainIntervalMs+');';
controlWindow.document.body.appendChild(script);
}
// write the start button to circumvent popup blockers
document.write('<input type="button" onclick="buildIntervalWindow();return false;" value="Start" />');
I'd recommend working out a better way to organize, write, etc. but at the least it should point you in the right direction. It should also work in a lot of diff browsers (in theory, only tested in chrome). I'll leave you to the rest.
Oh, and don't forget to build in auto-closing of the child window if the parent drops.

jQuery looping bug in iOS

Why would the difference between these two lines of code create a bug that cause jquery to loop endlessly in iOS(Safari and Chrome)? The loop did not occur in any other browser.
if ($('[name="loadingTime"]') != undefined) {...
vs
if ($('.loadingTime') != undefined) {...
When we targeted by class and not name attribute the loop bug went away. Any ideas or explanations?
Upon further investigation the bug was discovered in another part of the code. Here's what happened:
loadInterval: function() {
var settimer = $('[name="loadingTime]').val();
var interval = setInterval(function() {
if (settimer == 0) {
window.clearInterval(interval);
$('[id^="interstitial-container"]').remove();
};
settimer--;
if (settimer >= 0) {
$('.ncount').text(settimer);
}
}, 1000);
}
in
var settimer = $('[name="loadingTime]').val();
we missed a closing quote after loadingTime! which the js returned as undefined and iOS didn't handle it gracefully so var settimer wasn't set to zero so whenever that function loadInterval was called it was undefined and we checked whether we needed to load based on undefined or not. in our case it wasn't and continued to load over and over always getting an undefined response but without an error. I think...

Is setInterval handler called while my script running?

I planned to use setInterval to simply set a variable to false, which would be inspected by the main loop to stop. Example (note: this is an example only, the acutal code is not a while() loop which would be easy to reconstruct, but a quite complex, and long to execute script generated by a closed source software actually):
var running = true;
setInterval(function () {
if (running) {
console.log("Stopping now!");
running = false;
}
}, 100);
while (running) {
// do something ...
}
However it does not seem to work at least firefox drops a "busy script" box after a while. What's the problem with the code above? setInterval() may not be able to run if your script already runs otherwise? I couldn't find an exact specification what setInterval() does exactly.
I would need something like this, since I already have huge (and very long to execute) script, so I thought I will try to stop it after a while, then using setTimeout() to let the browser breath a bit and then continue: as the script itself does know its internal state so it can continue from any point, but it's not an option to modify the script actually ....
If it's not possible with setInterval, is there any alternative to this, without any modification in the "long to execute" code itself?
Thanks!
If it's not possible with setInterval, is there any alternative to this, without any modification in the "long to execute" code itself?
One possibility is to make that a web worker rather than trying to use it on the UI thread. Despite people repeatedly saying so, JavaScript is not single-threaded (JavaScript, the language, is silent on the subject), not even on browsers anymore. In the browser environment, there is one main UI thread, but you can spawn other worker threads (web workers). The worker(s) and the main UI code can communicate via postMessage / onmessage.
Here's an example of a web worker in action. This page uses JavaScript on the UI thread to start a web worker, which runs on a separate thread. The worker runs for 10 seconds, busily updating a counter (this is just to simulate a long-running, calculation-intensive process), and sends updates to the UI thread every second:
Main page:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Worker Example</title>
<style type="text/css">
body {
font-family: sans-serif;
}
</style>
<meta charset="UTF-8">
</head>
<body>
<script>
(function() {
var worker = new Worker("worker.js");
worker.onmessage = function(e) {
display("Worker says " + e.data);
};
display("Starting worker");
worker.postMessage("start");
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
</script>
</body>
</html>
worker.js:
this.onmessage = function(e) {
var counter, lastUpdate, now;
if (e.data === "start") {
// Loop without yeilding for 10 seconds, sending updates
// to the UI every second.
start = lastUpdate = Date.now();
counter = 0;
do {
++counter;
now = Date.now();
if (now - lastUpdate > 1000) {
lastUpdate = now;
this.postMessage(counter);
}
}
while (now - start < 10000);
this.postMessage("Done");
}
};
(You're not required to make the worker wait for a message to start, but it's fairly common.)
The problem is that Javascript is single-threaded. Rewrite your while loop to use setInterval itself and everything should work, since you will release the thread at the end of each loop.
You should use setTimeout or setInterval instead while loop. JS runs in single thread, so infinite loop will freeze your browser.
var running = true;
setInterval(function(){
if(running){
console.log('Stopping now!');
running = false;
}
}, 100);
(function loop(){
// Do yours loop stuff
if( running ){
setTimeout(loop, 0);
}
})();
You should consider using Worker or writing asynchronous code.
Or you can modify your code.
var running = true;
var past = Date.now();
while (running) {
// do heavy calculations ...
if ((Date.now() - past) > 10) {
running = false;
}
}
Of course, blocking loops aren't good idea, but I don't see good way to satisfy requirement:
If it's not possible with setInterval, is there any alternative to this, without any modification in the "long to execute" code itself?
JavaScript runs in a single threaded event loop. What this means is while your code is running no other code can run. This is why your callback does not get executed.
You can workaround this by also making your while(running) be asynchronous. Consider doing the following:
var running = true;
var monitor = setInterval(function () {
if (running) {
console.log("Stopping now!");
running = false;
clearInterval(monitor);
}
}, 100);
var work = setInterval(function() {
if (running) {
// do something
} else {
clearInterval(work);
}
}, 1);
Don't forget to call clearInterval!

Recursive Javascript Function For Online Status

I have the following javascript.
function isOnline() {
var status = navigator.onLine ? 'online' : 'offline',
indicator = document.getElementById('indicator'),
current = indicator.textContent;
// only update if it has change
if (current != status) {
// update DOM
indicator.textContent = status;
// trigger handler
handler[status]();
};
if(current == 'offline')
{
setInterval(checkServerStatus, 500)
checkServerStatus();
}
};
function checkServerStatus()
{
var img = document.createElement("img");
img.onload = function()
{
alert('yey!');
setInterval(isOnline, 500);
isOnline();
};
img.onerror = function()
{
alert('meh.')
};
img.src = "image-small.jpg"; //image on server(should be small so that intermittent checks are not bad)
}
$(checkServerStatus);
What I'd like to do is the following.
First call checkServerStatus() -- > if online run isOnline() every 500ms to keep checking the status of the website. In my isOnline code if I ever check that it is offline, then run checkServerStatus again, and if I'm still connected go back.
In addition, I'd like to add two things to this, when checkServerStatus fails, recursively call another function isOnline2 to check until it is online, where I then call checkServerStatus again.
The issue I am currently running into right now is that checkServerStatus keeps showing the 'yey' alert. I thought that, the function only starts once, and then using setInterval(isOnline, 500) will continue to run. After isOnline changes to offline, then I would run my checkServerStatus function again.
Any ideas on how to adjust this would be extremely appreciated.
Set your interval to a variable and then use clearInterval() when you want to stop your interval.
var interval = setInterval();
clearInterval(interval);
setInterval() runs a function on an interval endlessly, until cancelled with clearInterval().
In your case, I'd actually suggest not using setInterval but instead use setTimeout. This allows better control of execution: setTimeout runs once. At the completion of each function, you should be calling setTimeout to invoke either checkServerStatus or isOnline, as appropriate.
function isOnline() {
.....
if(current == 'offline') {
setTimeout(checkServerStatus, 500);
} else {
setTimeout(isOnline, 500);
}
};
It also prevents overlap: if, for example, checkServerStatus takes more than 500 ms to complete, with setInterval you'll be running it multiple times at the same time.

Categories

Resources