I have a function written in JScript (Not javascript) I need to suspend until a certain global variable becomes true.
The global variable is changed to true when another function is called after an ajax response:
function(req, event, data) {
globalVariable = true;
}
When I try to loop until the variable is true:
while (globalVariable!= true) {
}
I go into a busy waiting and the callback function is never called.
Some suggested the use of WScript.wait() but my app doesn't seam to know WScript.
SetTimeout() also won't help because it's asynchronic call and won't suspend my original function.
Any other suggestion?
Some more information regarding my question:
I want my script to call 2 functions:
waitWhileAjaxIsNotCompleted();
doSomthingElse();
I want the waitWhileAjaxIsNotCompleted() to click a button that submits an ajax request (implemented by A4J) and terminate upon the ajax completion.
In order for me to know when does tha ajax completed, I registered a function as a listener that will be awaken when the ajax completes. This function changes a globalVariable value.
My waitWhileAjaxIsNotComplete() goes into an infinite loop, waiting for the glovalVariable value to change. When it does change (After the listener has awaken), I can end the function ad continue with the doSomthingElse() function.
You can see more on the implementation on: QTP Web extensibilty toolkit and ajax
I can't remember what the heck I used
a few months ago since I don't use
Jscript anymore (not enough time)...
But I am currently looking in my
program to see if I still have the
script saved. I did the exact same
thing a few months back.
I'll post the code once I've found
it...
Sorry about that. I can't seem to find the code snippet. I must have deleted it... Typical of me though.
So, the only thing that I can think of until a better solution is available it to enter your code into an infinite loop, and simply break; out of it once the GlobalVariable returns true.
I hope this helps. I'm going to keep at it until I can either find the snippet or come up with a much better answer.
Related
I came across a peculiar issue when trying to make an ajax call and isolate the actions of the function to itself. Here is the code snippet
$(document).on('click', 'input.action', function(event) {
var self = this;
$.ajax({
url:'http://date.jsontest.com/',
method:'GET',
cache:false,
dataType:'json',
success:self.process,
error:function(){self.process(false);}
});
self.process = function(data) {
if (data) {
alert(data.time);
}
else {
alert("Operation Failed!");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="container">
<input type="button" value="Get Time" class="action"/>
</div>
Let me briefly explain what I am trying to do, on click of the button, I wish to receive some data from the server and display the data. I am using a process function to process the received data. In case of an error I reuse the process function in a different way to display the error message. I simply use the self variable to contain all the elements within the parent function. I fully understand the following:
What I know
I do not have to use the self to contain the process function because another method will not have access to it
Because the process method in the snippet above is declared after the ajax call for the program as far as it is concerned the process function is undefined.
I clearly know how to fix it.
Experiment:
Click on the Get Time button
Wait for as long as you want but see no result, which is expected because of the process function is declared after the ajax call
Click on the Get Time button again
It works now! Some time (which is probably not your time :P) is displayed now!!
What I wish to know:
What just happened? why does it work the second time and everytime after? Remember this only works for ajax calls, if it were the case that the assignment is retained in the function after calling it once, then this should work in every situation but it does not. Here is an experiment to show that it does not work the same way when ajax calls are not used: Fiddle - Experiment
The Solution:
I am adding a sample solution based on #Felix Kling's answer below. In the Sample Solution, there are two buttons Get Time and Get Date. I've attached the parameter to retrieve time in case of Get Time and date in the case of Get Date to the object self and it is interesting that once I click on Get Time nothing happens just like before but if I click on either Get Time or Get Date the second time only time is displayed.
What just happened?
In a simplified way, this:
var process;
// First click
ajaxCall(process); // process is still undefined
process = function() { ... };
// second click
ajaxCall(process); // process is defined
process = function() { ... };
The assignment to self.process "persists" between events because self refers to the same element.
Here is an experiment to show that it does not work the same way when ajax calls are not used: ...
It doesn't work in your fiddle because of one big difference: you are trying to execute process immediately. But it doesn't exist, so an error is thrown. At this point the script terminates and won't execute the rest of the function, where the function definition takes place.
In your example here, the execution of process is delayed. The script "doesn't know" that there is no function to call until the response was received.
There is nothing "special" going on here. Yes, accepted that the first time it returns undefined as it is yet to be defined.
But, you're attaching the function to the same element input.action. So, the next time, when you click the button, this already has the process method attached to it, so gets called when clicked again.
Try adding one more button with same class and click each once. Now though you've clicked the first button, clicking the second button will still not create an alert as it has not yet had the process function attached to it.
I tried looking for the answer, and this is my first post, so bear with me if I mess up in some way.
Basically my problem is this: I'm writing an extension for Chrome that uses jQuery. I have another extension that makes a timed $.ajax() request every 10 seconds. I need to find a way to run my code every time that timed ajax request and its callback function completes. Setting a timer for my own script can be done, although that's rather half-assed and doesn't work as well.
The problem can be illustrated thus:
//extension 1
function timedFunc() {
setTimeout(doStuff, 10000);
};
timedFunc();
//extension 2
//code to be run every time doStuff completes
I feel like there may be a very elementary solution to this problem but I appreciate the help.
There is (was) an event called DOMSubtreeModified.
But it has been deprecated so at tho moment there are really only workarounds available.
Why is the DOMSubtreeModified event deprecated in DOM level 3?
I can't advise on using this event as it hasn't even been implemented in all browsers.
But what you can do (easily) is just trigger you own event with all your ajax call!
Example:
fire your event when (any) ajax call completes:
$(document).ajaxComplete(function() {
$(document).trigger('domChanged');
}
and listen to it:
$(document).on('domChanged',function() {
alert("i changed the DOM tree!");
});
btw:
taken that you just want to react to ajax calls compleing... just use the .ajaxComplete() event:
http://api.jquery.com/ajaxComplete/
i didn't really understand what you are trying to say but i did understand your question in the title so here is my modest answer:
// a global variable for the documents content
var content=document.documentElement.innerHTML;
// return true if the document content has changed
function documentChanged(){
return content==document.documentElement.innerHTML;
}
I want to stop a script from executing, similar to what the Esc key does in Firefox. It stops all Javascript from running on that page as well as all gif animations.
Is there a function I could call which would stop everything?
Depending on how the offending module is organized, perhaps you can monkey-patch it without having to change its source code.
For example, if the annoying polling function is global or namespaced you can try to replace it with a useless stub:
//save the old version of the function, in case
//we need to restore it afterwards
var nasty_function = His.Namespaced.Evil.func;
//put our own stub in place
His.Namespaced.Evil.func = function(what, args, it , should, receive){
return somthing_that_signals_a_failed_poll;
}
No, there is nothing like that. And there's also no real reason for it: you write the code, you can make it stop doing things if you want to.
Plus: if there were such a function that stopped all JS activity... how would you make it start up again?
I'm looking for a good approach to sometimes pause an action (function/method call) until the user confirms that he wants to do a specific part of that action. I need to do this in an environment that doesn't allow code execution to stop (ActionScript in my case, but an approach for JavaScript should be identical).
To illustrate, this is a mock-up of the action before introducing the user prompt:
<preliminary-phase> // this contains data needed by all the following phases //
<mandatory-phase> // this will be always be executed //
<optional-phase> // this will always execute too, if in this form, but in some cases we need to ask the user if he wants to do it //
<ending-phase> // also mandatory //
What I need is to insert a conditional user prompt, a "Do you want to do this part?", and do <optional-phase> only if the user wants to.
<preliminary-phase>
<mandatory-phase>
if(<user-confirmation-is-needed> and not <user-response-is-positive>){
<do-nothing>
}
else{
<optional-phase>
}
<ending-phase>
When trying to do this in ActionScript/JavaScript I got something like this:
<preliminary-phase>
<mandatory-phase>
if(<user-confirmation-is-needed>){
askForConfirmation(callback = function(){
if(<user-response-is-positive>)
<optional-phase>
<ending-phase>
});
return;
}
<optional-phase>
<ending-phase>
Now both <optional-phase> and <ending-phase> are duplicated. Also because they use objects created in <preliminary-phase> I can't move them to external functions without passing all the data to those functions.
My current solution is that I enclosed each of <optional-phase> and <ending-phase> in some local functions (so that they have access to data in <preliminary-phase>) declared before I ask for confirmation and I call those functions instead of duplicating the code, but it doesn't seem right that the code is no longer in the order it's executed.
What would you guys recommend?
Notes:
1. askForConfirmation is a non-blocking function. This means that the code that follows its call is executed immediately (this is why I have a return; in my approach).
Note: I'm not 100% sure I get your exact circumstances.
The Command Pattern might be suitable here. It's similar to what people are suggesting.
You have an array of commands that get executed in order.
[<preliminary-phase>, <mandatory-phase>, <optional-phase>, <ending-phase>]
Just shift the commands off the array one at a time and call the execute method.
In the optional-phase, check to see if the user confirmation is required, if not then execute an optional code method which dispatches a command complete event, if it is required then show the alert, wait for an event, check the result and either dispatch a command complete event or call the optional method (which will run and then dispatch a command complete).
You can also create a tree of commands so can clearly state the flow of execution without having to mess with the array.
This is how programs like installation wizards work.
It's good in that the order of execution is nice and visible and your code is nicely broken down in to chunks, and the complexity of each step is encapsulated. For example, the optional-phase doesn't know anything about the ending-phase. The optional-phase only knows that the user might need prompted before executing and it handles all of that internally.
http://en.wikipedia.org/wiki/Command_pattern
"Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing..."
"the code is no longer in the order it's executed" seems fine to me actually. It's fine to have code that isn't written in the order it's executed just as long as it's clear. In fact, since your code executes in variable orders I think it's impossible for you to write it in the order it will execute without duplicating code, which is a far greater evil. Pick good function names and your approach would pass my code review.
<preliminary-phase>
<mandatory-phase>
var optional_phase = function() {
<optional-phase>
}
var ending_phase = function() {
<ending-phase>
}
if(<user-confirmation-is-needed>){
askForConfirmation(function(){
if(<user-response-is-positive>)
optional_phase();
ending_phase();
});
return;
}
optional_phase();
ending_phase();
Does this do what you're asking for?
<preliminary-phase>
<mandatory-phase>
if(<user-confirmation-is-needed>){
askForConfirmation(function(){
if(<user-response-is-positive>)
<optional-phase-as-local-function>
<ending-phase-as-local-function>
});
} else {
<optional-phase-as-local-function>
<ending-phase-as-local-function>
}
Not a huge change , but provided this flow works, optional phase is not repeated
<preliminary-phase>
<mandatory-phase>
if(<user-confirmation-is-needed>){
askForConfirmation(function(){
if(<user-response-is-negative>)
{
<ending-phase>
return;
}
});
}
<optional-phase>
<ending-phase>
Are you able to halt JavaScript execution without locking up the browser? The way you would normally halt execution is to do an infinite while()-loop, but in the case of FireFox, it locks up the browser until the loop has ended.
What's your take on this?
I am trying to override window.confirm() to implement my own dialog using HTML. I am doing this so I don't have to change existing code (it's a pretty big code-base).
I need to be able to halt execution to allow user-input; to in turn return a boolean like the standard confirm function does:
if (confirm("..."))
{
// user pressed "OK"
}
else
{
// user pressed "Cancel"
}
Update
To my knowledge; this cannot be done using setTimeout() or setInterval() since these functions execute the code thats given to them asynchronously.
confirm() prompt() and alert() are special functions--they call out of the JavaScript sandbox into the browser, and the browser suspends JavaScript execution. You can't do the same thing, since you need to build your functionality into JavaScript.
I don't think there's a great way to drop in a replacement without doing some restructuring along the lines of:
myconfirmfunction(function() {
/* OK callback */
}, function() {
/* cancel callback */
});
Either use callbacks or make your code Firefox-only. In Firefox with support for JavaScript 1.7 and higher, you can use the yield statement to simulate your desired effect. I have created a library for this purpose called async.js. The standard library for async.js includes a confirm method, which can be used as such:
if (yield to.confirm("...")) {
// user pressed OK
} else {
// user pressed Cancel
}
You cannot stop the event thread in JavaScript, so instead you have to work around the problem, usually by using callback functions. These are functions that are run at a later time, but can be passed around like any other object in JavaScript. You might be familiar with them from AJAX programming. So, for example:
doSomeThing();
var result = confirm("some importart question");
doSomeThingElse(result);
Would be converted into:
doSomeThing();
customConfirm("some importart question", function(result){
doSomeThingElse(result);
});
where customConfirm now takes a question and passes the result to the function it takes as an argument. If you implement a DOM dialog with a button, then connect an event listener to the OK and CANCEL buttons, and call the callback function when the user clicks on one of them.
There is an extension to the JavaScript language called StratifiedJS. It runs in every browser, and it allows you to do just that: halting one line of JavaScript code without freezing the browser.
You can enable Stratified JavaScript e.g. by including Oni Apollo ( http://onilabs.com/docs ) in your webpage like:
<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>
Your code would look like this:
var dom = require("dom");
displayYourHtmlDialog();
waitfor {
dom.waitforEvent("okbutton", "click");
// do something when the user pressed OK
}
or {
dom.waitforEvent("cancelbutton", "click");
}
hideYourHtmlDialog();
// go on with your application
the way you normally halt execution should hardly ever be an infinite while loop.
break up your work into parts, that you call with SetTimeout
change this:
DoSomeWork();
Wait(1000);
var a = DoSomeMoreWork();
Wait(1000);
DoEvenMoreWork(a);
to this:
DoSomeWork();
setTimeout(function() {
var a = DoSomeMoreWork();
setTimeout(function() {
DoEvenMoreWork(a);
}, 1000);
}, 1000);
I don't think there's any way to reasonably re-create the functionality of confirm() or prompt() in your own JavaScript. They're "special" in the sense of being implemented as calls into the native browser library. You can't really do a modal dialog of that sort in JavaScript.
I have seen various UI libraries that simulate the effect by putting an element on top of the page, that looks & acts like a modal dialog, but those are implemented using async callbacks.
You will have to modify the existing library, rather than replacing window.confirm.
I tried using tight looping for this. I needed to slow down a native event (which AFAIK is the only use case for a synchronous wait that can't be re-architected asynchronously). There are lots of example loops out there that claim not to lock up the browser; but none of them worked for me (the browser didn't lock up, but they prevented it from doing the thing I was waiting for in the first place), so I abandoned the idea.
Next I tried this - storing and replaying the event, which seems to be impossible cross-browser too. However depending on the event and how flexible you need to be, you can get close.
In the end I gave up, and feel much better for it; I found a way to make my code work without having to slow down the native event at all.