Javascript timeOut function - strange behavior - javascript

Im trying to implement a simple blckjack game, the problem is that the timeOut function is not working as I expect. I wrote some debugging messages to help you understand what I mean. With two words what I see is that the function is called once and than for some reason it exits from the function, program continues executing itself and than retunrs to the timeOut function...
What I want is to pause the program execution to wait user to choose whether to request new card ot to stop.
Thank you in advance!

Where is the waitForUserInput() method being called? Also, why use a timeout for grabbing user input? Why not simply subscribe to the mouse click event?

setTimeout will not stop exection of a script. It is just for delayed execution. After you call it - execution of program will be continued as usual, but after specified time - function passed as a first parameter will be executed. To wait for user input - take a look at click/keyup/keydown etc. events.
You should not do things like below in JS. JS always single thread and such loops will just freeze your interface. In yor case it looks like you should place onclick event on card block and put there a code which will do what you need.
while(true){
waitForUserInput();
if(requestCard){
userHand.hitMe();
var userHandCards = userHand.printHand().split(",");
displayCard(userHandCards[cardIndex]);
cardIndex++;
//console.log(">"+userHand.score());
if(userHand.score()>21){
break;
}
}else{
break
}
};
What I want is to pause the program execution to wait user to choose whether to request new card ot to stop
You should place some buttons with onclick handlers specified. And just run code you need depending on clicked button. Right now I do not see how user can say to your program about his choice. If that is a keybord command ("s" pressed than stop, "n" - next card ) - you can try to use document.onkeyup.

Related

In the following code, why is "OUCH" alerted?

In the following javascript code, I set a timer after 2 seconds, in which the handler is a function which alerts 'doneMessage'. When the prompt occurs, the next line should execute after I enter something or cancel the prompt.
function setTimer(doneMessage, n) {
setTimeout(function() {
alert(doneMessage);
}, n);
prompt('Enter a number');
doneMessage = "OUCH!";
}
setTimer("Cookies are done!", 2000);
So if I take more than 2 seconds on the 'prompt', the timer event should occur before the next line is executed. In this case 'doneMessage' should still be "Cookies are done!".
Why is "OUCH" alerted ?
Javascript is a single threaded language.
It cannot run more than 1 tasks at the same time.
Your current task is still being executed but held up by the prompt command.
Once you complete the prompt and exit the setTimer() function then that task is effectively finished.
At that point the doneMessage was set to "OUCH!"
Javascript is now free to do the next task.
Typically, it It loops all the timeout and see if there are any completed timer to execute and put them in a queue to execute next.
If you click on a button, it does not always immediately execute that button. It is place in the queue of task to execute next but given a high priority to make sure it is processed next. If Javascript wasn't currently in middle executing a task your button would be processed immediately.
Use the <input> tag and create your own prompt which is non-thread blocking and you will get the behaviour you want.

Recreating prompt(); functionality with <input>

I have a sort of a strange problem with the structure of my JS code. It is a convertor from Brainfuck to JavaScript. Then it runs the code it has generated.
With this in mind, I have noticed a problem with the prompt(); command. It seems to, in some situations, show the prompt box before the previous command (changing the DOM) finishes.
My solution is to show an <input type="text"> box, initially set to display:none in CSS. However, I need a way to wait for the input to change. I tried this code:
while (document.getElementById("input") == ""){}
But this freezes the DOM. I need a way to passively wait for any user input, then continue with the script.
Keep in mind, I can't use onkeydown, external functions, etc.
Thanks!
There's no way to stop script execution besides using native functions like alert, confirm, prompt.
Try wrapping your prompt inside a setTimeout. Start with a value of 0 to see if it works.
setTimeout(function () {
prompt('your prompt');
}, 0);
Using setTimeout with a value of 0 pushes the execution of the prompt to the back of the event loop, and may possibly run after your DOM updates.
Read more about this technique here: https://www.quora.com/What-does-setTimeout-with-a-0ms-delay-do
To wait for user input in a non-blocking way, you need to run asynchronous code. This you do by providing a callback function which should be called when a certain event takes place. In your case, this could be when the input value is submitted:
var inp = document.getElementById("inp");
inp.addEventListener('change', function(e) {
var value = this.value;
alert('you entered: ' + value);
// all code that needs the value, should come here,
// or should be called from here.
});
Exit field to submit value:
<input id="inp">

how to stop Javascript function execution?

My program has two buttons. One is for execute other program by using jquery load function. Whenever I click execute button, it runs some other program abc.php using load function for n times, with some time gap like k mins. These n and k will be filled with html inputs. Using jquery, will retrieve these and passing to that program file in url.
To call this function setTimeout was used.
Second one is for cancel execution.
Now my doubt is, suppose I want to stop that execution with cancel button. Is there any way to stop it ?
I would do this using boolean variable.
For example: Consider a method, perform logging.
fun () {
console.log("prints");
}
I would change it has
fun (isExecute) {
if (isExecute) {
console.log("prints");
}
}
Run fun (true); cancel fun (false);
Updates:
It seems you use setTimeout(), then it is too easy without above approach.
Run var inter = setTimeout(fun); cancel clearTimeout(inter);
FYI: The reason for assigning to a variable inter is then only you can clear this time interval.
set time for function:
timer = setTimeout(function(){$('#submenu').hide();},5000);
stop a function
clearTimeout(timer);

Can I interrupt javascript code and then continue on a keystroke?

I am porting an old game from C to Javascript. I have run into an issue with display code where I would like to have the main game code call display methods without having to worry about how those status messages are displayed.
In the original code, if the message is too long, the program just waits for the player to toggle through the messages with the spacebar and then continues. This doesn't work in javascript, because while I wait for an event, all of the other program code continues. I had thought to use a callback so that further code can execute when the player hits the designated key, but I can't see how that will be viable with a lot of calls to display.update(msg) scattered throughout the code.
Can I architect things differently so the event-based, asynchronous model works, or is there some other solution that would allow me to implement a more traditional event loop?
Am I making sense?
Example:
// this is what the original code does, but obviously doesn't work in Javascript
display = {
update : function(msg) {
// if msg is too long
// wait for user input
// ok, we've got input, continue
}
};
// this is more javascript-y...
display = {
update : function(msg, when_finished) {
// show part of the message
$(document).addEvent('keydown', function(e) {
// display the rest of the message
when_finished();
});
}
};
// but makes for amazingly nasty game code
do_something(param, function() {
// in case do_something calls display I have to
// provide a callback for everything afterwards
// this happens next, but what if do_the_next_thing needs to call display?
// I have to wait again
do_the_next_thing(param, function() {
// now I have to do this again, ad infinitum
}
}
The short answer is "no."
The longer answer is that, with "web workers" (part of HTML5), you may be able to do it, because it allows you to put the game logic on a separate thread, and use messaging to push keys from the user input into the game thread. However, you'd then need to use messaging the other way, too, to be able to actually display the output, which probably won't perform all that well.
Have a flag that you are waiting for user input.
var isWaiting = false;
and then check the value of that flag in do_something (obviously set it where necessary as well :) ).
if (isWaiting) return;
You might want to implement this higher up the call stack (what calls do_something()?), but this is the approach you need.

Avoiding a Javascript race condition

My users are presented a basically a stripped down version of a spreadsheet. There are textboxes in each row in the grid. When they change a value in a textbox, I'm performing validation on their input, updating the collection that's driving the grid, and redrawing the subtotals on the page. This is all handled by the OnChange event of each textbox.
When they click the Save button, I'm using the button's OnClick event to perform some final validation on the amounts, and then send their entire input to a web service, saving it.
At least, that's what happens if they tab through the form to the Submit button.
The problem is, if they enter a value, then immediately click the save button, SaveForm() starts executing before UserInputChanged() completes -- a race condition. My code does not use setTimeout, but I'm using it to simulate the sluggish UserInputChanged validation code:
<script>
var amount = null;
var currentControl = null;
function UserInputChanged(control) {
currentControl = control;
// use setTimeout to simulate slow validation code
setTimeout(ValidateAmount, 100);
}
function SaveForm() {
// call web service to save value
document.getElementById("SavedAmount").innerHTML = amount;
}
function ValidateAmount() {
// various validationey functions here
amount = currentControl.value; // save value to collection
document.getElementById("Subtotal").innerHTML = amount;
}
</script>
Amount: <input type="text" onchange="UserInputChanged(this)">
Subtotal: <span id="Subtotal"></span>
<button onclick="SaveForm()">Save</button>
Saved amount: <span id="SavedAmount"></span>
I don't think I can speed up the validation code -- it's pretty lightweight, but apparently, slow enough that code tries to call the web service before the validation is complete.
On my machine, ~95ms is the magic number between whether the validation code executes before the save code begins. This may be higher or lower depending on the users' computer speed.
Does anyone have any ideas how to handle this condition? A coworker suggested using a semaphore while the validation code is running and a busy loop in the save code to wait until the semaphore unlocks - but I'd like to avoid using any sort of busy loop in my code.
Use the semaphore (let's call it StillNeedsValidating). if the SaveForm function sees the StillNeedsValidating semaphore is up, have it activate a second semaphore of its own (which I'll call FormNeedsSaving here) and return. When the validation function finishes, if the FormNeedsSaving semaphore is up, it calls the SaveForm function on its own.
In jankcode;
function UserInputChanged(control) {
StillNeedsValidating = true;
// do validation
StillNeedsValidating = false;
if (FormNeedsSaving) saveForm();
}
function SaveForm() {
if (StillNeedsValidating) { FormNeedsSaving=true; return; }
// call web service to save value
FormNeedsSaving = false;
}
Disable the save button during validation.
Set it to disabled as the first thing validation does, and re-enable it as it finishes.
e.g.
function UserInputChanged(control) {
// --> disable button here --<
currentControl = control;
// use setTimeout to simulate slow validation code (production code does not use setTimeout)
setTimeout("ValidateAmount()", 100);
}
and
function ValidateAmount() {
// various validationey functions here
amount = currentControl.value; // save value to collection
document.getElementById("Subtotal").innerHTML = amount; // update subtotals
// --> enable button here if validation passes --<
}
You'll have to adjust when you remove the setTimeout and make the validation one function, but unless your users have superhuman reflexes, you should be good to go.
I think the timeout is causing your problem... if that's going to be plain code (no asynchronous AJAX calls, timeouts etc) then I don't think that SaveForm will be executed before UserInputChanged completes.
A semaphore or mutex is probably the best way to go, but instead of a busy loop, just use a setTimeout() to simulate a thread sleep. Like this:
busy = false;
function UserInputChanged(control) {
busy = true;
currentControl = control;
// use setTimeout to simulate slow validation code (production code does not use setTimeout)
setTimeout("ValidateAmount()", 100);
}
function SaveForm() {
if(busy)
{
setTimeout("SaveForm()", 10);
return;
}
// call web service to save value
document.getElementById("SavedAmount").innerHTML = amount;
}
function ValidateAmount() {
// various validationey functions here
amount = currentControl.value; // save value to collection
document.getElementById("Subtotal").innerHTML = amount; // update subtotals
busy = false;
}
You could set up a recurring function that monitors the state of the entire grid and raises an event that indicates whether the entire grid is valid or not.
Your 'submit form' button would then enable or disable itself based on that status.
Oh I see a similar response now - that works too, of course.
When working with async data sources you can certainly have race conditions because the JavaScript process thread continues to execute directives that may depend on the data which has not yet returned from the remote data source. That's why we have callback functions.
In your example, the call to the validation code needs to have a callback function that can do something when validation returns.
However, when making something with complicated logic or trying to troubleshoot or enhance an existing series of callbacks, you can go nuts.
That's the reason I created the proto-q library: http://code.google.com/p/proto-q/
Check it out if you do a lot of this type of work.
You don't have a race condition, race conditions can not happen in javascript since javascript is single threaded, so 2 threads can not be interfering with each other.
The example that you give is not a very good example. The setTimeout call will put the called function in a queue in the javascript engine, and run it later. If at that point you click the save button, the setTimeout function will not be called until AFTER the save is completely finished.
What is probably happening in your javascript is that the onClick event is called by the javascript engine before the onChange event is called.
As a hint, keep in mind that javascript is single threaded, unless you use a javascript debugger (firebug, microsoft screipt debugger). Those programs intercept the thread and pause it. From that point on other threads (either via events, setTimeout calls or XMLHttp handlers) can then run, making it seem that javascript can run multiple threads at the same time.

Categories