I am struggling with the fact that the flow of control in javascript is not what I'm used to. Not linear. Sometimes when I test I get the error message "A script is slowing down your browser" at times when everything should be stopped.
I spend ages looking for the bug. This time it was something really silly, a variable which stopped the function when it reached 350 px. Then I added a way to change the speed and sometimes this variable was incremented by 3 at each step. So it never reached 350, it went from 348 to 351.
So I was wondering if there was a "STOP!" command. Something which would leave the display of the web page in its current state but stop all running processes?
Debugger? It just creates a breakpoint, where you can analyse what's going on right now. I know it's not exactly what you're asking about, but it could work for your use case.
Usage
debugger; 😂
Can be used from within console too.
Learn more
https://www.w3schools.com/js/js_debugging.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
Depending on what you want here, the main answer is "no".
There are a few "hacks" (but they are quite intrusive and unreliable).
A good one (like mentioned in another answer here) is to throw the statement debugger; (that's all). Example:
let eggCount = 0;
function makeEggs(eggCount){
//Stop! The user is eating too much!!!
if(eggCount > 5){
debugger;
}
else{
make_egg("Over-hard");
return eggCount++;
}
}
However, this only works (or at least for chrome) if the console is open.
The second big one is to throw an error in your script (as shown by this post). It's hacky, and you can't have any try...catch loops (if you do then you have to throw an error, so you'd to re-throw that error).
let eggCount = 0;
function makeEggs(eggCount){
//Stop! The user is eating too much!!!
if(eggCount > 5){
throw "Egg overflow!";
}
else{
make_egg("Sunny side up");
return eggCount++;
}
}
The last big thing you can do (as mentioned by a comment here) is to re-write your logic.
From the looks of it, you have something like this:
let eggCount = 0;
function makeEggs(eggCount){
//Stop! The user is eating too much!!!
if(eggCount === 5){
throw "STOP!"
}
else{
make_egg("Over-hard");
return eggCount++;
}
}
Well, what if we did this?
eggCount = makeEggs(eggCount);
eggCount = 6;
eggCount = makeEggs(eggCount);
Since the equals sign checks for if it's just five, you can always bypass it.
This isn't a good idea, so we can re-wire our logic to do this instead:
let eggCount = 0;
function makeEggs(eggCount){
//Stop! The user is eating too much!!!
if(eggCount >= 5){
throw "STOP!"
}
else{
make_egg("Over-hard");
}
}
Now it will stop if it's 5 or greater.
This:
eggCount = makeEggs(eggCount);
eggCount = 6;
eggCount = makeEggs(eggCount);
will still throw the "STOP" error, even though it's greater than 5.
Sometimes, it's as simple as re-writing your logic.
You don't need the big hack-y stuff if it's as simple as just making your program smarter ;)
I've ran into this type of problem before.
I haven't encountered an incident yet where re-writing my logic doesn't help!
Related
Sometimes I make mistakes and get infinite loops in JavaScript (example: while(true){}). Firefox helpfully reports "Error: Script terminated by timeout" or that the memory allocation limit is exceeded. How can I change the length of this timeout? I want to shorten it during development.
I could also solve this problem by writing a function that I call inside the loop that counts iterations and throws an exception on too many iterations. But I'm also interested in how to change the timeout value.
I have not seen this timeout documented, and have not found it by searching.
Unfortunately the maximum recursion limit is not user configurable from within a page running javascript. The limits also vary across browsers.
This Browserscope test showcases the results of user testing from another StackOverflow question on the subject: What are the js recursion limits for Firefox, Chrome, Safari, IE, etc?
Aside from writing your own timeout or utilising a promise chain to process data, you won't be able to change the timeout yourself.
There are multiple ways to change the timeout of infinite loops.
One shorter method is setInterval:
setInterval(function() {
document.body.innerHTML += "Hello!<br>";
}, 1000) //This number is, in milliseconds, the interval in which the function is executed.
Another better method is window.requestAnimationFrame. This gives you a higher quality animation(see Why is requestAnimationFrame better than setInterval or setTimeout for more details); here's an example of it in motion:
function run() {
setTimeout(function() {
window.requestAnimationFrame(run);
document.body.innerHTML += "Hello!<br>";
}, 1000); // This sets an interval for the animation to run; if you take the setTimeout out the function will loop as quickly as possible without breaking the browser.
}
run();
D. Joe is correct. In Firefox, browse to about:config and change the number of seconds value in dom.max_script_run_time .
See http://kb.mozillazine.org/Dom.max_script_run_time for details--you can also eliminate the timeout.
This will partially answer your question, but here is how I handle such case. It is more a workaround than a fix.
IMPORTANT: Do not put this code in production environment. It should only be used in local dev while debugging.
As I tend to be debugging when I stumble upon this kind of case, I am mostly likely using console.log to output to console. As such, I override the console.log function as follow anywhere near the entry point of my app:
const log = console.log
const maxLogCount = 200
let currentLogCount = 0
console.log = function (...msg) {
if (currentLogCount >= maxLogCount) {
throw new Error('Maximum console log count reached')
}
currentLogCount++
log(...msg)
}
Then when I accidentally do this
while (true) {
console.log("what is going on?")
}
It will error out after 200 outputs. This will prevent the tab from locking for half a minute and having to reopen a new tab and bla bla bla.
It is usually just the browser's way of saying the script is out of memory. You could solve this by using for loops or creating and index variable and adding to it each time like so:
var index = 0;
while(true){
if(index > certainAmount){
break;
}
index++;
}
If you really want something to go on forever read about setInterval()
or setTimeout()
I'm working on a Google Scripts add on for Google Sheets, but I'm trying to get the script working before I actually set it up on the sheet. The code below works fine if I set a breakpoint somewhere in the extractNumbers function. If I just execute the code without breakpoints, I get an error:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
Here's the code:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
function phoneCheck(newCell,newHome,oldCell,oldHome) {
Logger.clear();
var newCell = extractNumbers(newCell);
var oldCell = extractNumbers(oldCell);
var newHome = extractNumbers(newHome);
var oldHome = extractNumbers(oldHome);
if (newCell === oldCell) {
return newCell;
exit;
} else if (newCell === oldHome && newHome === oldCell) {
return oldCell;
exit;
}
if (newCell === '' && oldCell !== '' ) {
return oldCell;
exit;
}
if (newCell !== oldCell && newCell !== oldHome) {
return newCell;
exit;
}
return "No value found";
exit;
}
function extractNumbers(input) {
Logger.log(input);
var str = input;
return str.replace( /\D+/g, '');
}
Now I realize my if/then logic is more than a bit inelegant, but for my purposes, quick and dirty is fine. I just need it to run.
ALSO, I have read of other novice JavaScript programmers having similar issues related to the sequence of code execution. If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too. Thanks!
EDIT: I put my code into a new fiddle and it works fine, but it continues to fail in Google Scripts editor unless running in debug mode with a breakpoint. The problem seems to be that the function parameters aren't available to the function unless there is a breakpoint. Anyone have access to Google Scripts that can try my updated code from https://jsfiddle.net/hrzqg64L/ ?
None of the suggestions got to the root of your problem - and neither did your answer, although you've avoided the problem by putting an enclosure around everything.
There's no AJAX, no asynchronous behavior - it's simpler than that. "Shadowing of parameters" is likewise a red herring. Bad coding practice, yes - but not a factor here.
If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too.
Sorry - no such thing. I can explain what's going on, but can't guarantee it will be accessible to novices.
The exception
Let's just clarify what causes the exception, or thrown error, that you've observed.
As written, extractNumbers() will throw an exception if it has a null parameter (or any non-string parameter) passed to it. If you choose to extractNumbers() then hit "run", you'll get:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
That is telling you that on line 36, which is return str.replace( /\D+/g, '');, the variable str contains an object that is undefined (...and has no replace() method).
For bullet-proof code, you would check your parameter(s) to ensure they are valid, and handle them appropriately. Sometimes that would be with a valid default, and other times you might return an error or throw an exception that is more explicit about the parameter problems.
Running code in Google's debugger
The only way to run code in Google's Debugger is to select a function, then choose "run" or "debug". Assuming you posted all your code, you had just two functions to choose from:
phoneCheck()
extractNumbers()
Whenever Google Apps Script runs any part of a script, the entire script is loaded and scanned to find all symbols & check syntax. The scope of all symbols is noted as well, and so are any dependencies between functions and global symbols (symbols outside of any closure, or block of code).
That takes some time. To speed things up when asked to execute a specific function, the global symbols are only evaluated if they are a dependency for the requested function or the functions it may call. There is another condition that will trigger evaluation of global symbols, and that is if there is a possibility that the debugger may need to stop and display values.
When this happens, any code that is outside a closure (outside a function, for example) will be executed. This is what you observed when you set breakpoints.
Why did it work when breakpoints were set?
As explained, just having a breakpoint set triggers evaluation of global symbols.
You start this script with a few lines of code that are not in any closure:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
It is that code which makes the only proper invocation of phoneCheck() with parameters. Because myVar is evaluated, phoneCheck() gets called with parameters, and in turn calls extractNumbers() with a defined parameter.
Unfortunately, because of the way the debugger works, you cannot choose to run that code yourself. You need to rely on these side-effect behaviors.
How to fix this?
Simple. Don't rely on global code to invoke functions under test. Instead, write an explicit test function, and call that.
function test_phoneCheck() {
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
}
Finally found the issue, but I don't fully understand it.
This question got me thinking about scope and how it might be different in the Google Script environment. I figured a simple workaround would be to enclose the entire script in its own void function, and it worked! Also, I simplified the script quite a bit with an array:
function init () {
var numberArray = ["a3", "a2", "o3", "o10"];
var myVar = phoneCheck(numberArray);
Logger.log(myVar);
function phoneCheck(myArray) {
var phoneString = '';
Logger.clear();
var arrayLength = myArray.length;
for (i = 0; i < arrayLength; i++) {
phoneString += myArray[i].replace(/\D+/g, '');
}
return phoneString;
}
}
Also, I realize the functionality of this script is different than the original, but I was really just trying to solve this problem. Now that I have, I can finish the script properly.
Thanks for all the suggestions, everyone! I learned a lot of good things, even though they turned out not to be the answer.
I am a student who is studying webview on android.
as I am a foreigner, I will thank you if you consider my mistakes on grammer...
I encountered a problem on making webview.
it is its "performance" when I use timer(setInterval method).
I am making a shooting game which is like "1945 strikers".
I made a effect which shows explosion-images using "Timer"(setInterval).
(This effect shows 14-pictures in order rapidly)
but, the problem is that my mobile phone can not show that effect naturally.
(it is stopped little by little)
I can not understand what is wrong.
exactly, I reduced "new" methods by using "pop" and turned off sounds.
I guess that the problem is based on the number of timer.
In my game, each bullet which hitted enemy occur explosion Timer.
and I duplicated this Timer to 10 as I thought it was not enough.
source code is like this.
=====call animation=======================
function drawCrash(x,y){
if (crashCount1 == 0) {
crashHereX = x;
crashHereY = y;
crashTimer1 = window.setInterval(crashAnimation1, interval);
crashCount1++;
}
else if (crashCount2 == 0) {
crashHereX2 = x;
crashHereY2 = y;
crashTimer2 = window.setInterval(crashAnimation2, interval);
crashCount2++;
}
... (total 10 methods)
======explosion animation==========================
function crashAnimation1() {
this.crashList=[crash01,crash02,crash03,crash04,crash05,
crash06,crash07,crash08,crash09,crash10,
crash11,crash12,crash13,crash14];
if (crashCount1 >= 13) {
window.clearInterval(crashTimer1);
crashCount1 = 0;
} else {
crashCount1+=1;
}
this.context.drawImage(this.crashList[crashCount1],crashHereX,crashHereY,50,50);
}
function crashAnimation2() {
this.crashList=[crash01,crash02,crash03,crash04,crash05,
crash06,crash07,crash08,crash09,crash10,
crash11,crash12,crash13,crash14];
if (crashCount2 >= 13) {
window.clearInterval(crashTimer2);
crashCount2 = 0;
} else {
crashCount2+=1;
}
this.context.drawImage(this.crashList[crashCount2],crashHereX2,crashHereY2,50,50);
}
... (total 10 methods)
is there anything which makes my game slow?
I have been debugging my source code using Chrome,(using F12 key)
but my laptop computer performs my source code well.
there isn't any problem!
you must hard to understand what I am saying...
what I want to know are like this.
should I reduce setInterval method to show the game performance naturally?
but, previous version (android 4.1.2) had NO problem! it performed naturally!
Now, I am using kitkat version(4.4.2)... I really hate this version.
Even I tried to downgrade my android phone!
it was hard for me to find "e.preventDefault();" it took 3-days for me to find...
is there anything which is better to debug JavaScript?(I am using Chrome F12 key)
is the "splice(index,1);" method occur "stopped phenomenon"(which I said above, "not natural")
when it is used many time? (in my game, many bullets are created and removed(new and splice))
I really want to know how to solve this problem...
Thank you very much.
I was trying to create a function in JavaScript for practice and the following code doesn't seem to be executing properly or as intended in the browser.The browser just keeps showing the busy sign and the computer literally hangs.Can anyone help me out with thius code or what the problem is:
function recluse() {
return " It is\ncalled Data.\n\nData is made of merely bits, yet it takes complex forms. Control\nconsists only of simple instructions, yet it performs difficult\ntasks. From the small and trivial, the large and complex arise.\n\nThe program source is Data. Control arises from it. The Control\nproceeds to create new Data. The one is born from the other, the\nother is useless without the one. This is the harmonious cycle of\nData and Control.\n\nOf themselves, Data and Control are without structure. The programmers\nof old moulded their programs out of this raw substance. Over time,\nthe amorphous Data has crystallised into data types, and the chaotic\nControl was restricted into control structures and functions.\n\n%% Short Sayings\n\nWhen a student asked Fu-Tzu about the nature of the cycle of Data and\nControl, Fu-Tzu replied 'Think of a compiler, compiling itself.'\n\nA student asked 'The programmers of old used only simple machines and\nno programming languages, yet they made beautiful programs. Why do we\nuse complicated machines and programming languages?'. Fu-Tzu replied\n'The builders of old used only sticks and clay, yet they made\nbeautiful huts.'\n\nA hermit spent ten years writing a program. 'My program can compute\nthe motion of the stars on a 286-computer running MS DOS', he proudly\nannounced. 'Nobody own a 286-computer or uses MS DOS anymore.', Fu-Tzu\nresponded.\n\nFu-Tzu had written a small program that was full of global state and\ndubious shortcuts. Reading it, a student asked 'You warned us against\nthese techniques, yet I find them in your program. How can this be?'\nFu-Tzu said 'There is no need to fetch water hose when the house is\nnot on fire.'{This is not to be read as an encouragement of sloppy\nprogramming, but rather as a warning against neurotic adherence to\nrules of thumb.}\n\n%% Wisdom\n\nA student was complaining about digital numbers. 'When I take the root\nof two and then square it again, the result is already inaccurate!'.\nOverhearing him, Fu-Tzu laughed. 'Here is a sheet of paper. Write down\nthe precise value of the square root of two for me.'\n\nFu-Tzu said 'When you cut against the grain of the wood, much strength\nis needed. When you program against the grain of a problem, much code\nis needed.'\n\nTzu-li and Tzu-ssu were boasting about the size of their latest\nprograms. 'Two-hundred thousand lines', said Tzu-li, 'not counting\ncomments!'. 'Psah', said Tzu-ssu, 'mine is almost a *million* lines\nalready.' Fu-Tzu said 'My best program has five hundred lines.'\nHearing this, Tzu-li and Tzu-ssu were enlightened.\n\nA student had been sitting motionless behind his computer for hours,\nfrowning darkly. He was trying to write a beautiful solution to a\ndifficult problem, but could not find the right approach. Fu-Tzu hit\nhim on the back of his head and shouted '*Type something!*' The student\nstarted writing an ugly solution. After he had finished, he suddenly\nunderstood the beautiful solution.\n\n%% Progression\n\nA beginning programmer writes his programs like an ant builds her\nhill, one piece at a time, without thought for the bigger structure.\nHis programs will be like loose sand. They may stand for a while, but\ngrowing too big they fall apart{Referring to the danger of internal\ninconsistency and duplicated structure in unorganised code.}.\n\nRealising this problem, the programmer will start to spend a lot of\ntime thinking about structure. His programs will be rigidly\nstructured";
}
var para=recluse().split("\n\n");
function reduce(func,length,array)
{
array.forEach(function(c)
{
length=func(length,c);
});
return length;
}
<!---TOP LEVEL FUNCTION FOR PROCESSING A VALUE WITH A FUNCTION AND CREATING AN ARRAY OF TH RESULTS------------>
function map(func,array)
{
var result_array=[];
array.forEach(function(c)
{
result_array.push(func(c));
});
return result_array;
}
<!-------------THE ALGORITHM FOR FINDING THE EMPHASISED TEXT AND THE FOOTNOTES WITHIN THE TEXT---->
function fragmenter(text)
{
var fragments=[];
function indexing(char)
{
var index=text.indexOf(char);
if(index==-1)
{
return text.length;
}
else
return index;
}
function ifAtStart(char)
{
var end=(char,1);
if(end==-1)
{
throw Error("No enclosing "+char);
}
var part=text.slice(1,end);
text=text.slice(end+1);
return part;
}
function normalText(text)
{
var end=reduce(Math.min,text.length,map(indexing,["*","{"]));//to check that the index is within the text only
var part=text.slice(0,end);
var text=text.slice(end);
return part;
}
while(text!="") <!---4------>
{
if(text.charAt(0)=="*")
{
fragments.push({type:"emphasised",
content:isAtFirst("*")});
}
else if(text.charAt(0)=="{")
{
fragments.push({type:"footnotes",
content:isAtFirst("}")});
}
else
{
fragments.push({type:"Normal",
content:normalText(text)});
}
}
return fragments;
}
console.log(fragmenter(para[1]));
There :
while(text!="")
{
// some code that doesn't change "text"
}
There is no way for text to change in the loop so your code can't finish.
If you're trying to iterate over the chars, you may do this :
for (var i=0; i<text.length; i++) {
if (text.charAt(i)=="*")
But I wonder if you missed the fact that when you call normalText(text), the normalText function can't change the variable it has, but only its own. You must share text. A solution is this :
function normalText() // REMOVED text SO IT USES THE ONE OF THE ENCLOSING SCOPE
{
var end=reduce(Math.min,text.length,map(indexing,["*","{"]));//to check that the index is within the text only
var part=text.slice(0,end);
var text=text.slice(end);
return part;
}
while(text!="")
{
if(text.charAt(0)=="*")
{
fragments.push({type:"emphasised",
content:isAtFirst("*")});
}
else if(text.charAt(0)=="{")
{
fragments.push({type:"footnotes",
content:isAtFirst("}")});
}
else
{
fragments.push({type:"Normal",
content:normalText()}); // REMOVED PASSING TEXT
}
}
function loopthrough (i) {
i++;
if (i <= 20) {
play_multi_sound("aud"+i);
$("#debug").html(i);
setTimeout("loopthrough("+i+");",242); }
else {
loops++;
$("#debug").html("rest");
$("#loops").html(loops);
setTimeout("loopthrough("+0+");",1000);
}
}
Does my code look like it is forking? since after about 3 loops it is litrally crashing the browser. I am using excessive HTML5 audio since I like to test new features and whilst im still a newbie at Javascript I really need this code to work. (Im making a simple beat game in canvas where you use a pong style paddle and each ball you hit of varying speed it will play a sound, thus making a cool beat)... Atm im just testing the capabilities of alot of audio being looped through at once.
So yeah my basic question is "Is my code efficient, is it forking and is there anyway of improving this greatly if you know of a better way?"
Thanks,
Tom C.
EDIT:
Just removed my loops++; (for some reason it was returning NaN even though it was defined as global) and it actually successfully looped 20 times without flaws.
I just did some tests, and I am sticking it here so that the code is clear.
function loopthrough (i) {
i++;
if (i <= 20) {
console.log("bla");
setTimeout(function(){ loopthrough(i); }, 242); }
else {
console.log("lala");
setTimeout(function(){ loopthrough(0); }, 1000);
}
}
loopthrough(0);
That worked fine and it never crashed. And it didn't fork either.
So, it's crashing on something else.
I would try this in another browser as well, and see if it crashes - could just be the FF beta 8 crashing.
Try removing 1 bit at a time from it and see if it starts to work - it's a good way to narrow down the culprit.
I bet it's the audio that's crashing it...
* update *
Try bumping up the timeout delay - it could be that the audio doesn't finish and then attempts to play again and is somehow backlogging.