16 May 2014

Guide to Javascript on Classic ASP

Disclaimer: As the title says, this is for Classic ASP with "Javascript".  If your project is using Visual Basic, you may be able to glean some information from this article, but it's not written with you in mind.

I've had some recent experience with a legacy system using Javascript (technically "JScript") on Classic ASP, and the thing I found most frustrating was the lack of coherent documentation available. Despite it's reputation, w3schools is still one of the best references available on the web.

I guess this shouldn't be a surprise.  It is a deprecated platform, and they don't call it "Classic" for nothing. But there are still legacy systems out there which need to be maintained. If the system is purely in maintenance mode, you can probably get along just by reading the existing code and holding your nose. But if you need to add features and make significant changes, it's worth knowing some of Classic ASP's secrets so you can take advantage of the modern Javascript ecosystem.

Note: This is meant to be a reference for anyone who's forced to work with Classic ASP. In no way am I condoning using it by choice.  But if you've got to use it - use it right.

Javascript in Classic ASP is ECMAScript 3


First thing to be aware of is that the code you're writing, at it's core, is ECMAScript 3.  Another way to think of it: If your code runs in IE8 (minus the DOM API, obviously) it'll run in Classic ASP.

I've seen some developers approach Classic ASP code like it's some ancient writing which only the old masters knew how to interpret.  It's not.  There are only 6 things which are not, strictly speaking, Javascript: Request, Response, Server, Application, Session, and ASPError.
Your biggest challenge is learning to live without features from ES5, or finding appropriate shims.

The global scope cannot be directly manipulated

This is the biggest WTF to get your head around if you're used to coding in browsers or NodeJS. Trying to work with the global scope object as "this" will cause errors, giving developers the false impression that modern libraries won't work with Classic ASP.

Say you've got a third party library (like UnderscoreJS) that declares itself like so:

(function () {
  this.myExport = {};
}).call(this);

If I try to run this in Classic ASP, it will throw an error.
You can easily work around it, though it is somewhat tedious:

var surrogate = {};
(function () {
  this.myExport = {};
}).call(surrogate);
var myExport = surrogate.myExport;

Use <script src="" runat="server"> to include code without tags


Most Classic ASP I know uses the #include directive provided by IIS to compose source files.  The directive works by essentially pasting the entire file content into the directive location, like so:

include.asp:
<script runat="server">
var myInclude = {};
</script>

main.asp:
<!-- #include file="include.asp" -->
<script runat="server">
var myProgram = {include: myInclude};
</script>

Results in:
<script runat="server">
var myInclude = {};
</script>
<script runat="server">
var myProgram = {include: myInclude};
</script>

The downside to this is that you can't use any Javascript code quality tools.  They'll start to parse your file, find the tags, and throw syntax errors. This prevents you from doing style checks, code coverage, and code metrics. It can also cause headaches for editors and IDEs.

Instead you can use <script src="" runat="server"> to include files into your tags, just like any ".js" file into HTML:

include.js
var myInclude = {};

main.asp:
<script src="include.js" runat="server"></script>
<script runat="server">
var myProgram = {include: myInclude};
</script>

Using this method, there's noth... very little to stop you using the same tools enjoyed by NodeJS developers. Though you obviously need to be configure IIS so that it doesn't expose your code files as static resources.
That would be bad...

Code in <% %> tags is parsed before <script runat="server"></script> tags

This was a bit of a head scratcher when I first discovered it.  But sure enough, code in <% %> tags executes before <script runat="server"></script> tags (stackoverflow).

<script runat="server">Response.Write("first");</script>
<%Response.Write("second");%>

Result: second, first

My recommendation is: Don't use <% %> tags.

It's too easy to create tag soup, and you're better off using <script src="" runat="server"> anyway for JS code tooling.

Core ASP objects don't produce Javascript primitives

var param = Request.QueryString('param');
param == "test"; // true
param === "test"; // false
String(param) === "test"; true

This means you tried to call "param.substring(1)", it would throw an error saying that "substring" was undefined.  So you need to make sure you wrap results from core ASP objects in String(), Number(), or Boolean() before you try to use them.

That about does it.
To all the poor bastards out there stuck working on Classic ASP: This is for you.

See more on Know Your Meme

2 comments:

  1. Thanks for the great tips. I've been fighting with JScript and the core ASP objects. They have default properties that VBScript uses natively, but JScript doesn't. Those default properties are not really documented anywhere that I can find. I wasn't aware of the String() Number() and Boolean() functions. Those must be aware of the default properties and make it much easier to get what you're looking for out of the objects.

    One tip you didn't have, but I found really helpful for enumerating the ASP collections, is the Enumerator() function:
    ```
    for(var objEnum = new Enumerator(collection); !objEnum.atEnd(); objEnum.moveNext()){
    var key = objEnum.item();
    var item = collection(key);
    //do something with item, which probably has a default property to get the value, like item.Item or something similar; not all have that though
    }
    ```
    I don't remember where I found that...usually I comment a URL reference in my code when I find golden nuggets like that.

    ReplyDelete
    Replies
    1. Good point - I'd forgotten about old Enumerator. Thanks for that!.

      Which reminds me - I found this gem a few years ago: Typescript in Classic ASP
      https://github.com/bysanches/ASPTypeScriptSample

      It includes a few great secrets about Classic ASP, including this one about the script execution order:
      https://github.com/bysanches/ASPTypeScriptSample#script-execution-order

      Delete