slow down execution of javascript's eval - javascript

I have created a little robot like the Karel robot (Wikipedia) which is based on javascript.
Karel4Web
The robot can be controlled with some simple commands such as "forward", "turnright" and so on.
The user can write a javascript program to control the robot which then goes through javascripts "eval()" function so that the robot moves.
The problem is that I want the robot to move slowly so that you can see what he is doing and so that you can highlight the current code line in the editor.
Current method: Parsing
At the moment I have solved this (in the offline version) by parsing each line in the textarea and then building a stack of action which are then executed one after another with window.setTimeout. But this is of course limited because I have to write parsing code for every little javascript language contruct which is much work and error prone.
Some additional information to this:
Parsing version: http://abi-physik.de/_niki2/niki.php
Parsing version js code: http://abi-physik.de/_niki2/js/niki.js
Important functions are at the bottom of the script: run(), execute()
I am currently parsing the user script line by line and adding the actions to a stack. If the parser encounters an "if" it will begin a new stack and add all actions to that stack. if the parser then encounters an "}" it will close the "if" stack and continue to add actions to the base stack.
Any idea to improve this?

I would say have those functions register to some queue instead of having them execute the JavaScript directly.
var moveQueue = [];
function forward(){
moveQueue.push(_forward);
}
function _forward(){
alert("move forward");
}
function backward(){
moveQueue.push(_backward);
}
function _backward(){
alert("move backward");
}
Than when it runs you would use a setTimeout and
function run(){
var curStep = 0;
function go(){
moveQueue[curStep]();
curStep++;
if(curStep<moveQueue.length){
window.setTimeout(go,500);
}
}
}
You still would need to parse it out to figure out the if statement logic, but this is one of many ways that will allow you to control the speed of execution.

Javascript doesn't have a sleep() function, so yes, using setTimeout or setInterval is the way to go.
You could parse the 'instructions' first, assemble an array of actions that need to be carried out, then use setInterval to arrange for a function to be regularly called which takes the next instruction and carries it out (or clears the interval, if there are no more instructions waiting to be processed).

Related

How to stop a setInterval Loop in Javascript outside of code without refreshing the browser?

This may be a quite naive question but I really need some help.
Prior to writing this post, I was programming on JSBin. Turns out without me realizing, I ran a setInterval loop prompting for userInput and it kept on looping, making me unable to click anywhere to change the code to fix the loop. It kept on repeating and repeating. It got to the point where I had to refresh and lose all my hard-written-code (I was not logged in, so my code was not saved)! I want to avoid that next time.
So, my question is how do I stop any such kind of setInterval Loops, so that I am able to access my code and change it and re-run it. Below is a code that demonstrates my issue, if you try running it on JSBin.com (obviously, it is not the code I wrote before). As you can see, I can not click on my code to change it (or save it) in any way, which means I lose all my code!
This may seem like a useless question, but I really want to know ways to fix it and perhaps fixing it from the developer tools will help me be familiar with the overwhelming set of tools it has :P. So please help me if you know a solution.
Thank you for taking your time to help me! I appreciate it.
setInterval(demo,1);
function demo()
{
var name = prompt("Enter your name: ");
}
Another option is to search the developer tools "Elements" panel for the iframe (this should be doable even if the main document is unresponsive due to prompt's blocking) - then, just right click the iframe element and remove it, no need to type any Javascript. (or, if you want you can select the iframe with querySelector and remove it, eg document.querySelector('iframe').remove())
That's kind of a hack and should only be used in cases like the one exposed in OP but,
About all implementations use integers as timerid that just get incremented at every call.
So what you can do, is to clear all timeouts that were created on the page.
To do so you need to first get to which timerid we are, then call cleatTimeout or clearInterval (they do the same) in a loop until you reach the last call:
function stopAllTimers() {
const timerid = setTimeout(_=>{}); // first grab the current id
let i=0;
while(i < timerid) {
clearTimeout(i); // clear all
i++;
}
};
btn.onclick = stopAllTimers;
// some stoopid orphan intervals
setInterval(()=>console.log('5000'), 5000);
setInterval(()=>console.log('1000'), 1000);
setInterval(()=>console.log('3000'), 3000);
const recursive = () => {
console.log('recursive timeout');
setTimeout(recursive, 5000);
};
recursive();
<button id="btn">stop all timeouts</button>
Assuming the dev tools are closed, hit esc and f12 nearly simultaneously. This should open the dev tools. If it doesn't keep trying until it does.
Once they are open, hit esc and f8. Again, retry til it halts javascript execution at some arbitrary point in the code.
In the "sources" tab locate the generated script for what you wrote (offhand I don't know how it would look like from within JSBin) and literally delete the var name = prompt("Enter your name: "); line. Hitting f8 again will continue execution as if the "new" code is running. This should free you up to copy/paste your code from the site itself before you refresh the page

style.display changing after Array Sort

I want to display a simple loading message before a sort, but the display changes from none to block after the sort even though I call the sort after. I even tried using setTimeout (2 seconds) to change the display then call a dummy function to sort the stuff.
function sort(i) {
document.getElementById("loading").style.display = "block";
array.sort(function(a, b) {
return a[i].localeCompare(b[i]);
});
}
Browsers don't rush to repaint the page while JS is busy working (on the assumption that there will probably be other DOM changes that they should batch together for the repaint).
You'll need to free up the event loop to allow a repaint between your two statements.
Move the call to array.sort into a function and call it after a delay (e.g. with setTimeout or requestAnimationFrame).

javascript adding code at the beginning and at the end of every function

for logging purpose i would like to launch a method at the beginning and at the end of every function.
function myFunction1(){
//log.start() automatically
doStaff();
//log.stop() automatically
}
is there any way to do that?
Cheers

Is there any solution to end an endless loop function?

Is there any solution to escape from the endless function, code like this:
var endless = function(){
while(true){};
}
killWhenTimout(endless, 5000);
I am looking for a solution like killWhenTimeout, killWhenTimeout will kill the loop if time is out.
Any suggest will be appreciated.
If endless function doesn't require any special API, for example manipulating DOM, you could run it within a WebWorker. And then terminate it after the timeout, if it is still running.
Take a look at this article for details - https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers.

Avoiding loop when at run-time parse a javascript code

I realized a javascript parser built in a web page.
A user can put a javascript code in the text-area like:
var i = 0;
i++;
var y = i * 10;
document.write(y);
that is parsed in order to generate some outputs (e.g., document.write stream, and so on).
The function parse is called when textarea change event is generated.
function parse(text) {
try {
....
eval(text);
} catch (e) {
....
return {
status : false, output : ..., ... : ...
};
}
return {
status : true, output : ...., ... : ...
};
}
Everything works well but I have problem when a user writes a loop in the text area (e.g., for(var i=0; i<10; ), while(true))
because the application goes in loop.
To avoid this problem, I would ask you all some questions/solutions for this problem:
Are there some javascript libraries or functions that allow to
eval a javascript code but are loop-free?
Can I ask to execute my parse function but in a fixed time? After such time I would generate an exception that stops the eval function.
Before to call the eval(text) I can call a checkIfThereAreLoops function that analyses the text seeking for patterns like for(var i=0; i<10; ) or while(true). Is this a good solution? Can I use a regular expression to seek these patterns?
If you are trying to see whether arbitrary code will terminate, you will be in for a rough time the Halting Problem is NP-Hard.
So you are right to think that you would either need a preventative measure on your parse function that either times out or dismisses unsafe input.
I'm not aware of a way to interrupt eval without the browser imposing a 'this script is running too long' limit, so you would want to sanitize the input and not evaluate anything with a loop: This will be tricky since you can't just search for constructs such as for, while etc and avoid recursive function calls.
This is a difficult problem to solve...
One 'hacky' solution could be to insert a unique variable declaration into the top of the entered code (hidden of course) and to increment this variable every other line from within the input code (again, hide these insertions and allow for syntax constructs becoming broken. Also insert sanity checks at each increment if unique_var > 99999 exit; (where 99999 is some limit you impose).
This should at least stop infinite loops.

Categories