I want the Javascript code can manipulate some object in html infinitely,
But, I can only use setTimeout("function()", 0) and can't use while(1)
examples:
while: https://gist.github.com/Asoul/e5dd3bd38eef4ca239cb
setTimeout : https://gist.github.com/Asoul/bda34fa2f70e4077ec12
I don't know why the while(1) can't work on my chrome
SetTimeout can work sometimes, but if there are many setTimeout in my code or some unknown reasons, it will lag.
example: http://www.csie.ntu.edu.tw/~b00902036/run_neo/run_neo.html
(Use up, left, right to play. I tried hard to avoid lags, but sometimes it still happen.)
I want use pure CSS, not canvas, and want the game can play without lags.
The main reason you cannot use while is because javascript is single-threaded. If you use while(1), the function will never exit and all other interactions are frozen.
SetTimeout can work sometimes, but if there are many setTimeout in my
code or some unknown reasons, it will lag.
This is also because of single-threaded nature of javascript, if there is a function taking long time to complete, it will dominate the main thread.
want the game can play without lags.
You need to avoid long-running operation inside all of your functions. If you cannot avoid that, try using setTimeout to split a long-running operation into many pieces.
For example: if you have a for-loop processing 100 records, you could split it into 10 separate iterations.
Related
In a browser, I am trying to make a well-behaved background job like this:
function run() {
var system = new System();
setInterval(function() { system.step(); }, 0);
}
It doesn't matter what that System object is or what the step function does [except it needs to interact with the UI, in my case, update a canvas to run Conway's Game of Life in the background], the activity is performed slowly and I want it to run faster. But I already specified no wait time in the setInterval, and yet, when I check the profiling tool in Chrome it tells me the whole thing is 80% idle:
Is there a way to make it do less idle time and perform my job more quickly on a best effort basis? Or do I have to make my own infinite loop and then somehow yield back time to the event loop on a regular basis?
UPDATE: It was proposed to use requestIdleCallback, and doing that makes it actually worse. The activity is noticably slower, even if the profiling data isn't very obvious about it, but indeed the idle time has increased:
UPDATE: It was then proposed to use requestAnimationFrame, and I find that once again the slowness and idleness is the same as the requestIdleCallback method, and both run at about half the speed that I get from the standard setInterval.
PS: I have updated all the timings to be comparable, all three now timing about 10 seconds of the same code running. I had the suspicion that perhaps the recursive re-scheduling might be the cause for the greater slowness, but I ruled that out, as the recursive setTimeout call is about the same speed as the setInterval method, and both are about twice as fast as these new request*Callback methods.
I did find a viable solution for what I'm doing in practice, and I will provide my own answer later, but will wait for a moment longer.
OK, unless somebody comes with another answer this here would be my FINAL UPDATE: I have once again measured all 4 options and measured the elapsed time to complete a reasonable chunk of work. The results are here:
setTimeout - 31.056 s
setInterval - 23.424 s
requestIdleCallback - 68.149 s
requestAnimationFrame - 68.177 s
Which provides objective data to my impression above that the two new methods with request* will perform worse.
I also have my own practical solution which allows me to complete the same amount of work in 55 ms (0.055 s), i.e., > 500 times faster, and still be relatively well behaved. Will report on that in a while. But wonder what anybody else can figure out here?
I think this is really dependent on what exactly you are trying to achieve though.
For example, you could initialize your web-worker on loading the page and make it run the background-job, if need be, then communicate the progress or status of the job to the main thread of your browser. If you don't like the use of post-message for communication between the threads, consider user Comlink
Web worker
Comlink
However, if the background job you intend to do isn't something worth a web-worker. You could use the requestIdleCallback API. I think it fits perfectly with what you mentioned here since you can already make it recursive. You would not need a timer anymore and the browser can help you schedule the task in such a way that it doesn't affect the rendering of your page (by keeping everything with 60fps).
Something like =>
function run() {
// whatever you want to keep doing
requestIdleCallback(run)
}
You can read more about requestIdleCallback on MDN.
OK, I really am not trying to prevent others to get the bounty, but as you can see from the details I added to my question, none of these methods allow high rate execution of the callback.
In principle the setInterval is the most efficient way to do it, as we already do not need to re-schedule the next call back all the time. But it is a small difference only. Notably requestIdleCallback and requestAnimationFrame are the worst when you want to be rapidly called back.
So, what needs to be done is instead of executing only a tiny amount of work and then expect to be called back quickly, we need to batch up more work. Problem is we don't know exactly how much work we should batch up before it is too much. That can probably in most cases be figured out with trial and error.
Dynamically one might take timing probes to find out how quickly we are being called back again and preemptively exit the work (loop of some kind) when the time between the call-backs is expired.
I have a 'for' loop wich have to loop around 10000000000 times so that i get the disered result.
However, it ends up all the time freezing the browser ...
It's not like that 'for' is working infinitly but as i told, it's very long
Is there some way to solve my problem with javascript or i should use another language ?
In a compiled language and if you do virtually nothing in the loop, you can achieve 1,000,000,000 iterations a second on a desktop processor. So your loop would take 10 seconds.
If your Javascript environment is interpreted (and not compiled), you probably won't get more than 10,000,000 iterations and your loop will take 1000 seconds (16 minutes).
If you additionally have somewhat more expensive operations within the loop (and Javascript is likely to allocate memory for simple operations, which is expensive), you're in the order of 1,000,000 iterations per seconds and your code takes 10,000 seconds (close to 3 hours).
You might want to think about a better algorithm...
The issue that you are seeing is because javascript is single threaded in the browser. Your for loop is holding on to the thread for the entire time that it is running. The problem is that this thread also handles interactions with the interface. There may be other possibilities, but the two ways that I can think of to fix this would be:
Use a Web Worker (docs), this solution will not work for older browsers though
If possible, break your loop into smaller chunks that can be ran using setTimeout. After each chunk is processed, use setTimeout to schedule the next chunk to be processed in say 100ms. You will need to play with the numbers, but that should free up the thread so that it can respond to events. This will make the calculation take longer but should make it so the browser doesn't freeze up.
Don't do it. To run this kind of Javascript code in a browser makes no sense. If you really want to do this on the client side, you should consider writing some kind of browser extension, where you have more control on the CPU and local storage.
You might want to separate that loop in smaller chunks and run them sequentially, with an appropriate progress system. If you are talking about a loop, a multithreaded system will not help you, assuming the result n+1 is based on the n result.
Consider using a server-side script with a queue or job mechanism and just push notifications to the client. As Teemu said, the time (even in a fast paced situation) is huge.
I'm trying to write some JavaScript to run against IE8. It's to do with sorting a moderately large set of data (actually, for 99% of users its a very small set of data - but as always, there's some edge cases) . I've been investigating ways to execute a long script on IE8 without either blocking the UI or causing the 'Long Running Script' message.
A popular solution is to use window.setTimeout to stagger function calls and then return that variable at the end asynchronously. The common advice is to write a recursive function and call it with
window.setTimeout(fn, 1);
because this is supposed to add the call to the thread's event queue. UI operations will be interleaved with setTimeout calls and the browser will remain responsive. IE8 won't moan, the idea goes, because its statement counter is reset when the timeout is invoked.
But I have a problem. I've found that in IE8, the long running script exception only disappears if the timeout is long enough.
I've written some functions that increment a number to 3 million using staggered function calls that each perform 50,000 n++ operations. These functions perform many operations (actually, massively more than even my worst use case), but none should break IE's documented 5 million instruction limit. Here's the thing, though: if I stagger the functions with a 1ms timeout, I get a long running script warning in IE8 half way through (after several function calls). If I stagger them with a 15ms timeout, I don't. How come? Is this something to do with the granularity of the Win32 timing API?
Here's a JSFiddle: http://jsfiddle.net/yb79vx7h/1/ , and an embedded version you can try for yourself in IE8
: http://jsfiddle.net/yb79vx7h/1/embedded/result/
Edit: curiously, I can replicate the same problems with the 15ms code if I count to 9 million using 600,000 iterations. That prompts the 'Stop running this script?' dialog in IE8 too. So it seems to be to do with the amount of actions versus the timeout length.
As part of my Chrome Extension, I am performing a few regex replaces on a lot of (upwards of 3000) elements on the document end event. In the worst cases, in Chrome 34.0.1847.116 m on a pretty decent PC, the operation can take >180 seconds to complete, and during this time, the webpage is frozen.
Is there, and if so, what is the best way to either mitigate the operation over a longer time span, or give the operation a "lower priority" so that it doesn't take 100% while running.
The script is pretty much nested jQuery each functions all running a regex replace using a large expression. These expressiond search for 3000-4000 words and then replaces it with some html. An example one is (searching for specific reddit names)
/(\s|/u/|^)(name1|name2|name3|...|name500)([^\w]|$)/
If it helps, you can see the full source here.
Thank you for your time.
You can run the long operations in a new thread using the setTimeout function and a callback on completion.
See Javascript Create New "Thread"
Is it possibly to do things asynchronously in javascript (AJAX aside)? For example, to iterate multiple arrays at the same time. How is it done? A brief example would be nice. Searching for this was hard, due to all the ajax pollution, which is not what I am looking for.
Thanks in advance.
Use web Workers. But remember that it is a very new feature and not all browsers are fully supported.
You could use setTimeout.
setTimeout(function () { iterateArray(array1); reportDone(1); }, 0);
setTimeout(function () { iterateArray(array2); reportDone(2); }, 0);
I'm not sure how concurrent it will be, but it is an asynchronous programming model.
As stated by Grumdrig you can write code like this:
setTimeout(function () { iterateArray(array1); reportDone(1); }, 0);
setTimeout(function () { iterateArray(array2); reportDone(2); }, 0);
But it will still not run concurrently. Here's a general idea of what happens after such timeouts are called:
Any code after the setTimeout calls will be run immediately, including returns to calling functions.
If there are other timers in queue that are at or past their delay or interval time, they will be executed one at a time.
While any timer is running, another might hit its interval/delay time, but it will not be run until the last one is finished.
Some browsers give priority to events fired from user interaction such as onclick and onmousemove, in which case the functions attached to those events will execute at the expense of timer accuracy.
This will continue until there is an opening (no previously called timers or event handlers requesting execution). Only then will the functions in the example code be run. Again one at a time, with the first one likely but not certainly executing first. Also, I'm venturing a guess that some browsers might impose a minimum delay time, which would make any timers set with a delay of 0 milliseconds be run even later than expected.
Obviously there is no performance advantage to running code like this. In every case it will make things take longer to complete. However in cases where a single task is taking so long it freezes the browser (and possibly trips "Script is taking too long" browser warnings), it can be helpful to break it up into smaller faster executing pieces that run sequentially after some delay time, thus giving the browser some time to breathe.
Web Workers have been mentioned, and if you are not concerned about IE compatibility then you can use them for true concurrency. However there are some severe limitations on their use imposed for security reasons. For one they cannot interact with the DOM in any way, meaning any changes to the page still must be done synchronously. Also all data passed to and from workers is serialized in transit, meaning true Javascript objects cannot be used. That being said, for intensive data processing, Web Workers are probably a better solution than breaking a function up into multiple timer delayed tasks.
One new development in this field is HTML5 Web Workers.
JavaScript is normally single threaded; you cannot do several things at once. If your JavaScript code is too slow, you will need to offload the work. The new way is to use web workers, as others have noted. The old way is often to use AJAX and do the work on the server instead. (Either with web workers or with AJAX, the arrays would have to be serialized and the result deserialized)
I have to agree with MooGoo, i also wonder why you would run through such a big array in one go.
There's an extension to JavaScript called StratifiedJS, it allows you do multiple things at once as long as they're asynchronous. Also, webworkers are an awkward "solution" that just make things more complicated, also, they don't work in IE.
In StratifiedJS you could just write.
waitfor {
// do something long lasting here...
}
and {
// do something else at the same time...
}
// and when you get here, both are done