So, I'm creating a bot to play a video game online (completely legally, there's a server for bot competitions, don't worry). The code is in JavaScript, which I'm just picking up now, and I'm having trouble telling the bot to do something, then wait either by time or by condition until doing something else.
So far, I'm simply wrapping everything in gigantic setTimeout commands, but this is extremely inelegant.
There's not too much code that's relevant to post, but essentially I've made up a lot of code that does things like move to a specific location, brake, chase another player, etc. Most work with a recursive setTimeout command - press certain buttons, reset variables, then start the function again if the condition isn't met. If I want to move to a specific location then brake when I finish with that, generally I'd put code likes this:
moveTarget(target);
brake();
[...Execute rest of code...]
However, JavaScript executes both of these commands at the same time, which obviously doesn't work very well. Is there a way to make something more like this (Or the equivalent with a condition instead of a specified time):
moveTarget(target);
wait3Seconds();
brake();
[...Execute rest of code...]
Without needing to do this:
moveTarget(target);
setTimeout(function(){
brake();
[...Execute rest of code...]
},3000);
Given how many of these situations I'll have, my code will end up looking like a gigantic mess of nested setTimeouts, which is not very pretty. Is there a better way? I'm already using JQuery, so I'm perfectly willing to use that if necessary.
A little background...
JavaScript does not handle concurrency in the same way as other programming languages you may be used to. Instead, JavaScript has only the one main thread, and instead has a queue for registering then handling events in order as they occur.
For this reason, it is very important to not do things that would block the thread for long periods of time (like a function such as Thread.sleep() would do). That is why you instead should use setTimeout or setInterval for things like this.
You could always create a custom sleep function to write code in the style you are requesting. This might be something like:
function sleep(millis) {
var startTime = Date.now();
while (Date.now() < startTime + millis) {}
}
But this would be VERY, VERY BAD. This would freeze the page while this sleep function is running.
Back to your problem...
You basically need to refactor your code to be more "eventful". Rather than having large, linear chunks of code within the same block, you should write your JavaScript code to use callbacks and timeouts.
So the last code block you showed is really the paradigm you should be following with JavaScript:
moveTarget(target);
setTimeout(function(){
brake();
[...Execute rest of code...]
},3000);
However, you can certainly clean things up a LOT, if instead of [...Execute rest of code...], you split that apart into other functions and call them from within your setTimeout callback. Of course, keeping your code blocks small and concise is a good rule of thumb in any programming language.
You might also interested in checking out the request animation frame function.
There isn't really a better way to do that. The reason is that any sort of waiting is going to trigger a task that goes into the task queue. Since javascript is single threaded, it has to use these task queues and as a result it will just keep on executing instructions past the setTimeout if instructions are present.
In order to execute code after your delay, it has to be in the timeout callback or it will execute immediately.
You could do this if you created all of your methods in a chain that had a wait command, similar to the jQuery queue system.
$("<div>").queue(function(next){
// do a
a();
next();
}).delay(3*1000).queue(function(next){
// after 3 seconds do b
b();
next();
}).delay(3*1000).queue(function(next){
// after 3 more seconds do c
c();
next();
}).dequeue(); //.dequeue() starts it, only has to be called to make a queue that isn't currently running begin.
so all you would have to do is maintain the same chain and keep adding to it.
Related
I have seen a lot of function examples for async javascript containing setTimeout, AJAX calls, etc.
Obviously these all have a certain delay meaning the flow of the script is impacted. But I was wondering, what if I have something like this:
function init() {
this.initSlider();
this.testLog();
}
function initSlider() {
// find multiple items and build up a slider instance
// for each of these elements.
}
function testLog() {
console.log('test);
}
If initSlider possible takes a long time will it simply run my testLog function first?
I am currently a bit unsure about this. I know there might be plenty of examples on the flow of javascript but I can't find ones where a simple function would just take a longer time to run.
It is totally depend on what is there inside initSlider(). Although initslider() is heavy function and do not contain any asynchronus statement
then testLog() will not execute first.
Javascript stores all statements in callstack and they will be executed one after the other.
If there is asynchronus statement then it removes that statement outof the callstack and there is chance of your testLog() to execute.
so for your question my answer will be DEPENDS ON CODE INSIDE initSlider()
Javascript is a technology that runs single threaded. When you use asynchronous methods like AJAX or setTimeout the javascript engine processes those parts one by one (if one is waiting something than switching to another and then back and etc...). You can see the javascript's power on async tasks with Node.js. I guess this blog is very good to understand the Javascript and async methods: click_me!
What is the point of doing setTimeout(fx, 0) in node?
This is not asynchronous or even non-blocking, as the async function is really the setTimeout, not your fx, and after setTimeout has run asynchronously, you will end up running fx which will block your code anyway.
Doing the setTimeout with 0 to call a function fx will just wait until the stack is empty to run fx, but then while fx is running you won't be able to accept any requests, right?
So is setTimeout(fx, 0) just a way of telling node 'hey, run this whenever you can'? Is there any way to trully run async functions in Node?
If your question is:
Can node run functions in parallel at the same time?
Then the answer is yes, but you have to use a web worker.
The paradigm of asynchronosity in node is different from traditional definitions. The expectation is that you don't run too many ultra-long running functions in node. This way, effective asynchronosity is achieved.
Node is good for some things, not for others, just like any environment.
For a more detailed answer, refer here
As for setTimeout(...,0) calls; sometimes giving a break during a time consuming task to allow calls in the queue have their share of processing can be required. Dividing tasks in different ways can save you from these; but still, this is not really a hack, it is just the way event queues work. Also, using process.nextTick for this aim is much better since when you use setTimeout, calculation and checks of the time passed will be necessary while process.nextTick is simply what we really want: "Hey task, go back to end of the queue, you have used your share!"
If I understand your question correctly the answer would be the following:
As JavaScript is a single threaded language it is still able to deal with two things separately.
Using setTimeout(fx, 0) allows you to push the function or operation within the setTimeout Function in a "waiting qeue". As soon as the Stack of operations is completed the function gets put onto the execution stack and gets executed.
More detailed information about that can be found in this video
I have a web application which uses jQuery/JavaScript heavily. It holds a large array in memory, and the user filters it by typing in a textbox.
Problem: When the filtering algorithm runs, the application becomes non-responsive and the browser may even ask the user whether to let the script continue.
Optimally, I would like the filter function to run in a separate thread, to avoid non-responsiveness. Is this possible in any way? Alternatively, I would like to show a rotating hourglass or similar, but browsers seem unable to display animated GIFs when running heavy scripts.
What is the best way of attacking the problem?
Browsers execute scripts in the main event processing thread. This means any long running scripts can holdup the browser queue.
You should split your filter logic into chunks and run them on timeout callback's. You may use a gap of 0 mills between executions. 0 milli's is just a suggestion to the browser, but the browser will use the gap between subsequent callbacks to clear its event queue. Timeout's is generally how long running scripts are ought to be executed in the browser environment to prevent the page from "hanging".
This type of job is what Web Workers were designed for, support is patchy, but improving.
Expanding on my comment from earlier, given that you are processing an array you are probably using a for loop. You can easily refactor a simple for loop to use setTimeout() so that the work is broken up into chunks and the browser gets a chance to handle screen paints and user interaction between each chunk. Simple example:
// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, startIndex, endIndex, delay) {
function doIteration() {
if (startIndex < endIndex){
fn(startIndex++);
setTimeout(doIteration, delay);
}
}
doIteration();
}
// pass your function as callback
timeoutLoop(function(i) {
// current iteration processing here, use i if needed;
}, 0, 100, 0);
Demo: http://jsfiddle.net/nnnnnn/LeZxM/1/
That's just something I cobbled together to show the general idea, but obviously it can be expanded in various ways, e.g., you might like to add a chunkSize parameter to timeoutLoop() to say how many loop iterations to do in each timeout (adding a conventional loop around the call to fn()), etc.
Quite often see in JavaScript libraries code like this:
setTimeout(function() {
...
}, 0);
I would like to know why use such a wrapper code.
Very simplified:
Browsers are single threaded and this single thread (The UI thread) is shared between the rendering engine and the js engine.
If the thing you want to do takes alot of time (we talking cycles here but still) it could halt (paus) the rendering (flow and paint).
In browsers there also exists "The bucket" where all events are first put in wait for the UI thread to be done with whatever it´s doing. As soon as the thread is done it looks in the bucket and picks the task first in line.
Using setTimeout you create a new task in the bucket after the delay and let the thread deal with it as soon as it´s available for more work.
A story:
After 0 ms delay create a new task of the function
and put it in the bucket. At that exact moment the UI thread is busy
doing something else, and there is another tasks in the bucket
already. After 6ms the thread is available and gets the task infront
of yours, good, you´re next. But what? That was one huge thing! It has
been like foreeeeeever (30ms)!!
At last, now the thread is done with that and comes and gets your
task.
Most browsers have a minimum delay that is more then 0 so putting 0 as delay means: Put this task in the basket ASAP. But telling the UA to put it in the bucket ASAP is no guarantee it will execute at that moment. The bucket is like the post office, it could be that there is a long queue of other tasks. Post offices are also single threaded with only one person helping all the task... sorry customers with their tasks. Your task has to get in the line as everyone else.
If the browser doesn´t implement its own ticker, it uses the tick cycles of the OS. Older browsers had minimum delays between 10-15ms. HTML5 specifies that if delay is less then 4ms the UA should increase it to 4ms. This is said to be consistent across browsers released in 2010 and onward.
See How JavaScript Timers Work by John Resig for more detail.
Edit: Also see What the heck is the event loop anyway? by Philip Roberts from JSConf EU 2014. This is mandatory viewing for all people touching front-end code.
There are a couple of reasons why you would do this
There is an action you don't want to run immediately but do want to run at some near future time period.
You want to allow other previously registered handlers from a setTimeout or setInterval to run
When you want to execute rest of your code without waiting previous one to finish you need to add it in anonymous method passed to setTimeout function. Otherwise your code will wait until previous is done
Example:
function callMe()
{
for(var i = 0; i < 100000; i++)
{
document.title = i;
}
}
var x = 10;
setTimeout(callMe, 0);
var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';
That is the reason I use it.
Apart from previous answers I'd like to add another useful scenario I can think of: to "escape" from a try-catch block. A setTimeout-delay from within a try-catch block will be executed outside the block and any exception will propagate in the global scope instead.
Perhaps best example scenario: In today's JavaScript, with the more common use of so called Deferreds/Promises for asynchronous callbacks you are (often) actually running inside a try-catch.
Deferreds/Promises wrap the callback in a try-catch to be able to detect and propagate an exception as an error in the async-chain. This is all good for functions that need to be in the chain, but sooner or later you're "done" (i.e fetched all your ajax) and want to run plain non-async code where you Don't want exceptions to be "hidden" anymore.
AFAIK Dojo, Kris Kowal's Q, MochiKit and Google Closure lib use try-catch wrapping (Not jQuery though).
(On couple of odd occasions I've also used the technique to restart singleton-style code without causing recursion. I.e doing a teardown-restart in same loop).
To allow any previously set timeouts to execute.
I guess that once it's executed it's on the queue, but in the queue is there any assurance it will invoke exactly after X milliseconds? Or will other heavy tasks higher on the queue delay it?
The semantics of setTimeout are roughly the same as in a web browser: the timeout arg is a minimum number of ms to wait before executing, not a guarantee. Furthermore, passing 0, a non-number, or a negative number, will cause it to wait a minimum number of ms. In Node, this is 1ms, but in browsers it can be as much as 50ms.
The reason for this is that there is no preemption of JavaScript by JavaScript. Consider this example:
setTimeout(function () {
console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')
The flow here is:
schedule the timeout for 100ms.
busywait for 5000ms.
return to the event loop. check for pending timers and execute.
If this was not the case, then you could have one bit of JavaScript "interrupt" another. We'd have to set up mutexes and semaphors and such, to prevent code like this from being extremely hard to reason about:
var a = 100;
setTimeout(function () {
a = 0;
}, 0);
var b = a; // 100 or 0?
The single-threadedness of Node's JavaScript execution makes it much simpler to work with than most other styles of concurrency. Of course, the trade-off is that it's possible for a badly-behaved part of the program to block the whole thing with an infinite loop.
Is this a better demon to battle than the complexity of preemption? That depends.
The idea of non-blocking is that the loop iterations are quick. So to iterate for each tick should take short enough a time that the setTimeout will be accurate to within reasonable precision (off by maybe <100 ms or so).
In theory though you're right. If I write an application and block the tick, then setTimeouts will be delayed. So to answer you're question, who can assure setTimeouts execute on time? You, by writing non-blocking code, can control the degree of accuracy up to almost any reasonable degree of accuracy.
As long as javascript is "single-threaded" in terms of code execution (excluding web-workers and the like), that will always happen. The single-threaded nature is a huge simplification in most cases, but requires the non-blocking idiom to be successful.
Try this code out either in your browser or in node, and you'll see that there is no guarantee of accuracy, on the contrary, the setTimeout will be very late:
var start = Date.now();
// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);
// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}
Unless the interpreter optimises the loop away (which it doesn't on chrome), you'll get something in the thousands. Remove the loop and you'll see it's 500 on the nose...
setTimeout is a kind of Thread, it holds a operation for a given time and execute.
setTimeout(function,time_in_mills);
in here the first argument should be a function type; as an example if you want to print your name after 3 seconds, your code should be something like below.
setTimeout(function(){console.log('your name')},3000);
Key point to remember is, what ever you want to do by using the setTimeout method, do it inside a function. If you want to call some other method by parsing some parameters, your code should look like below:
setTimeout(function(){yourOtherMethod(parameter);},3000);
The only way to ensure code is executed is to place your setTimeout logic in a different process.
Use the child process module to spawn a new node.js program that does your logic and pass data to that process through some kind of a stream (maybe tcp).
This way even if some long blocking code is running in your main process your child process has already started itself and placed a setTimeout in a new process and a new thread and will thus run when you expect it to.
Further complication are at a hardware level where you have more threads running then processes and thus context switching will cause (very minor) delays from your expected timing. This should be neglible and if it matters you need to seriously consider what your trying to do, why you need such accuracy and what kind of real time alternative hardware is available to do the job instead.
In general using child processes and running multiple node applications as separate processes together with a load balancer or shared data storage (like redis) is important for scaling your code.
setTimeout(callback,t) is used to run callback after at least t millisecond. The actual delay depends on many external factors like OS timer granularity and system load.
So, there is a possibility that it will be called slightly after the set time, but will never be called before.
A timer can't span more than 24.8 days.