var gfPgDone;
function ProcessPage(sPgTxt) {
alert( sPgTxt );
}
function CollectPageInfo( sURL ) {
gfPgDone= false;
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4) {
ProcessPage( req.responseText );
gfPgDone= true;
}
}
req.open( "GET", sURL, true ); // true for async operation
req.send();
}
The critical (and possibly confusing) factor is that the operation is asynchronous; that is, when you call CollectPageInfo, control resumes immediately -- but the new data is not yet available. So lines 7 and 12 manipulate a globally-visible Boolean flag variable so that your program can know when the page has been loaded. That whole asynchronous issue is covered in detail, below.
<html>
<script>
//---------------------------------------------------
function DoTest() // on button click
{
// instantiate and exercise ActiveX objects, etc.
oDivDisplayArea.innerHTML="<b>test complete!</b>";
}
</script>
<!-- I like to put the U/I stuff at the bottom -->
<!-- ***************************************** -->
<body onload="window.resizeTo(400,300);">
<div align=right><input type=button value="restart"
onclick= "document.location.reload();"></div>
<input type=button value='DoTest' onclick='DoTest();' </input>
<div id=oDivDisplayArea>
<font color=gray>(stuff will be displayed here)</font>
</div>
</body>
</html>
Rename the file to give it an extension of .HTA ... and that is your starting "HTA skeleton." Double click the HTA file's icon to run it:
<html>
<script>
var gfPgDone; // global variable
function ProcessPage( sPgTxt ){
oDivDisplayArea.innerText= sPgTxt;
}
function CollectPageInfo( sURL ) {
gfPgDone= false;
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4) {
ProcessPage( req.responseText );
gfPgDone= true;
}
}
req.open( "GET", sURL, true ); // true for async operation
req.send();
}
//---------------------------------------------------
function DoTest() // on button click
{
CollectPageInfo( "http://www.google.com/" );
}
</script>
<!-- ***************************************** -->
<body onload="window.resizeTo(400,300);">
<div align=right><input type=button value="restart"
onclick= "document.location.reload();"></div>
<input type=button value='DoTest' onclick='DoTest();' </input>
<div id=oDivDisplayArea>
<font color=gray>(stuff will be displayed here)</font>
</div>
</body>
</html>
When you click the [DoTest] button, the program starts the process that reads the Google home page. A few milliseconds later, the raw HTML of that page is displayed:
var gasListOfURLs=
new Array("http://www.google.com/", "http://www.yahoo.com/", "http://www.msn.com/");
function DoTest()
{
var req = new XMLHttpRequest();
for (var j=0; j<gasListOfURLs.length; j++ ) {
var sURL= gasListOfURLs[j];
req.open( "GET", sURL, false ); // false for ***synchronous*** operation
req.send(); // <----- control is stuck here until done
ProcessPage( req.responseText );
// alert( req.responseText );
}
}
The problem with this is that the application seems to hang. The U/I goes dead. The window does not get updated and buttons are unresponsive until the entire sequence is finished. So we need to work out a way to request the pages one-at-a-time without that happening.
var gasListOfURLs=
new Array("http://www.google.com/", "http://www.yahoo.com/", "http://www.msn.com/");
var gnIdxStart=0;
var gnIdxEnd= 2;
var gnIdxCurr= gnIdxStart;
var gnTimerID;
function DoTest() {
gnIdxCurr= gnIdxStart= 0;
StartNextPage();
}
function StartNextPage() {
oDivDisplayArea.innerText= "reading...";
CollectPageInfo( gasListOfURLs[gnIdxCurr] );
gnTimerID= setInterval( "TimerProc();", 500 ); // twice per second
}
function TimerProc() {
if ( ! gfPgDone ) {
oDivDisplayArea.innerText += "."; // visual feedback
return;
}
//----------- else page is done and has been processed... start next page
clearInterval( gnTimerID ); // avoid recursing
gnIdxCurr++;
if ( gnIdxCurr > gnIdxEnd ) {
return;
}
StartNextPage();
}
With this mechanism in place, all you need to do is define the list of pages and provide your own ProcessPage() function. Even pages that take a long time to load will be handled correctly.
var gdtFailSafe= new Date().valueOf()+30000; // max wait= 30 seconds
...
function TimerProc() {
var n= new Date().valueOf();
if ( n > gdtFailSafe ) {
alert("timed out");
}
...
If you have IE8 or later installed, you can set a timeout in the XMLHttpRequest object itself. In that case, when there is a timeout, the response value is null.
var req = new XMLHttpRequest();
...
req.timeout=30000; // 30 seconds, then call it bad
req.open( "GET", sURL, true ); // true for async operation
...
function ProcessPage( sPgTxt ){
if ( sPgTxt==null ) {
// handle the timeout
}
...
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (2)
Author
Commented:Addendum to the article:
The XMLHttpRequest object might not be available if you have an old enough system (if your IE is stil in the 6.x range). It is still possible to accomplish all of the above by using the related ActiveX object that does the same thing. Check out this great EE article that shows how to instantiate that object on older systems:Reading Files Into Your Web Page With JavaScript
https://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_3327.html
See the getRequestObject() function in the first code snippet.
Commented:
http://api.jquery.com/category/ajax/
this makes creating ajax easyer and even cross browser compatible.