Reputation: 17
I am writing a language for educational purpose, which should run in web browsers. The language compiles to JavaScript.
So there is the problem of endless loops and recursion. Until that moment I thought the solution would be to have the runtime implemented as a WebWorker and a button on the ui, to terminate it if it runs to long.
I just found out, while testing my language, that the web worker isn't really terminated, by calling : runtime.terminate()
;
At least not until his last job has finished, i haven't tested what happens if it would be finished. Even in the documentation I found so far, its stated that it stops execution immediately.
So even if the user can continue working that way, the running worker in the background can use up resources and lead to at least a not responding browser.
So I need any way to terminate the execution in case of an endless loop or recursion, in response to a user event. As I din't find any way to put a thread to sleep in JavaScript, this doesn't work either, or is there something like sleep for web workers?
Have you got any suggestions what I could do?
Upvotes: 2
Views: 688
Reputation: 5572
I was curious about this recently, and I've just tested it. In Chrome and Firefox (as of 2023), an infinite loop is interrupted by worker.terminate()
.
However, in Chrome, it takes a couple of seconds for termination to occur, whereas in Firefox, it happens instantly. I posted a crbug issue about this here.
You can test the behaviour in your browser of choice by running this code:
let myWorker = new Worker(URL.createObjectURL(new Blob([`
self.onmessage = function() {
let i = 1;
while(i++){
if(i % 10000000 === 0) console.log(i);
}
}
`], { type: 'text/javascript' })));
myWorker.postMessage('start');
setTimeout(() => {
console.log('Terminating worker...');
myWorker.terminate();
}, 5000);
In Chrome, the console.log(i)
's occur for a couple of seconds after Terminating worker...
is logged, whereas in Firefox, Terminating worker...
is always the last thing that's logged.
Upvotes: 2
Reputation: 17
Yes I'm writing a compiler.
As working on this approach I must mention, it might be that the overhead for the user might not be much, but the impact on compilation is really huge... It's like building a VM on top of Javascript...
What I got to this point is that additional to the above mentioned points I need also to:
-need an complex indexing system for function naming -take care of variable allocation -have to solve expressions in series -...
That's why I am looking for a more elegant variant...
Upvotes: -1
Reputation: 17
Thanks for the response, I have thought about this way, so actually I wouldn't need the web worker for it. So the downside of this approach is:
1) That I would have to implement the loops as recursive function calls ...
And the bigger problem 2) The segment size has to be limited to one command, that this approach actually works, so I would have to wrap each command into a function that calls the next one, which would be a huge overhead...
Thats why I am looking for a way around, if there is any?
Upvotes: -1
Reputation: 4081
I would do it like this:
1) Have your compiler generate code such that instead of executing the program from start to finish, it breaks it up into segments - for example, the body of a loop or the body of a function could be a segment.
2) Each segment should end with a timeoutId = setTimeout(nextSegment, 0)
. This allows the web worker to receive and respond to asynchronous events in between executing segments.
3) When you want to terminate the web worker, use window.postMessage()
to send it an asynchronous message.
4) Inside the web worker, have an event handler that, upon receiving that message, does a clearTimeout(timeoutId)
.
Upvotes: 2