Amazon.ca Widgets

High performance JavaScript htmlEncode

I recently had to encode lot of strings to HTML in client-side javascript.  There’s a lot of find-replace procedures we can find all over the web, but I think that the most reliable way to encode string is to use the browser itself.

One very easy method to encode a string, that we find everywhere, is this one: 

function htmlEncode(_s){
  return $("<span />").text(_s).html()
}

If we use that quick jQuery function, we know that the result is totally safe, by allowing the browser to do the job on our behalf.

But, using the DOM is sometimes the cause of a slow application…
Does this method is reliable if we need to convert thousands of strings?

I did the test, by repeating the conversion 100000 times.

The previous function, creates a new “span” on every call, and modify the innerHTML of it.

Chrome console “performance monitor” shows that there are 3 DOM nodes created on each call. It takes an average of 2200 ms to run the loop, and generates lots of garbage collection to remove these old DOM items.

Take 2

So, let’s try to re-use the previous span instead without re-creating it.

var $span;
function htmlEncode(_s){
   $span = $span || $('<span />');
   return $span.text(_s).html();
}

This time, on each call, 2 DOM nodes instead of 3 are created.
And, the average time goes down to 1600 ms instead of 2200.

Take 3

Then, I tried to see what jQuery does, to see if it’s possible to re-use the inner text objects that are re-created on each call.

Now, try that 100% non-jquery method. (That you can achieve by using jquery and editing the childNodes directlly…)

var spn, txt;
function htmlEncode(_s){
   if (!spn) {
      spn = document.createElement("span");
      txt = document.createTextNode("");
      spn.appendChild(txt);
   }
   txt.data = _s;
   return spn.innerHTML;
}

That final version of our custom htmlEncode function looks very powerful!

Now, 0 nodes are created on each loop (3 on the first call), we always re-use the same 3 nodes.
And, the loop time is now 100 ms, with absolutely no garbage collection!

Summary

Look at these analysis from the Chrome console.

You can try it by yourself on that demo page I used to generate the previous tests.

How to use jQuery “$” in WordPress

If you add javascript into WordPress, you will certain try execute some jQuery functions sooner or later.

And, you will get an error telling that $ is undefined.

I think that jQuery embedded into wordpress do not declare the “$” variable, as it may confuse some users with all the $ server-side variables from PHP.

All jQuery functions can be run using “jQuery” variable instead of “$”.

But, if you want to use “$” as you did before, be warned that just typing:
$ = jQuery;
can interfere with some existing functions that may use the $ variables for other purposes.

So, what I propose is to encapsulate all your functions inside a self-called function like this:

(function($){
   ...
   $('body').addClass("cool");
   ...
 })(jQuery);

You put all your code inside that function, the “$” is available, and it doesn’t interfere with all other code.

How to make your server-side javascript code private in IIS

You learned that you can use Server-Side Javascript mixed in our ASP Classic VBScript application.

Next, you want to create tons of javascript files, and mix them with your old ASP. You can name them “.asp”, or “.inc”, like you did with your old VBScript files.  But, what about using intellisense in a standard editor from these extensions?

The best way to use intellisense in your favorite editor, like Visual Studio Code or anything else, is to name these files with the .js extension.

But, there’s a security issue.  If you name these files like that, they should be returned to your client in plain text if called from a web browser.  You don’t want your server-side code to be exposed through IIS.

What you need to do, is just put all these files in a specific folder, in which you will disable all IIS handlers, by using the following steps.

  1. In your application root, create a folder called private.
  2. In that folder, create a web.config file, and add this content:
<system.webServer>
  <handlers>
    <clear />
  </handlers>
</system.webServer>

You can now add all your server-side JS in that folder, and they will private to your ASP code.

If you call that js file in the browser, you will get a 404:

From your ASP page in the root, include them like this:

<script runat="server" language="javascript" src="private/code.js"></script>

That’s all! Happy Coding.

How to use Try Catch in ASP Classic

The worst part of Classic ASP in VBScript is Error Handling.

You need to type “on error resume next”, then, check, on every line, check if the previous one generates an error using [If Err.Number <> 0 then …]. That’s a real pain.

When you need solid error handling inside an ASP – VBScript sub or function, there’s a very simple method you can apply.

Just turn your existing error-handling-needed function into JavaScript, and use Try-Catch!
What? Javascript in ASP Classic?
Yes you can! It’s called JScript, it’s ECMAScript 3 compatible, and it just works.

Also, it’s totally compatible with your existing VBScript application, that will be able to call that JS method without any issue.  Even all your application VBScript variables will be shared between VB and JS.

Sample:
100% VBScript file:

<%
function fct1
	fct1 = true
	on error resume next
	' do something that can crash
	dim i : i = 1
	i = i / 0
	if err.number <> 0 then
		fct1 = false
		response.write err.number & "<br>"
		response.write err.description & "<br>"
	end if
	on error goto 0
end function

sub sub1
	dim value : value = fct1()
	response.write "result: " & value
end sub

call sub1()
%>

Now, the same, using mixed VBScript/ Javascript

<script runat="server" language="javascript"> 
function fct1(){
	try{
		// do something that can crash 
		var i = 1;
		i = parseINT(i); // <- typo
		return true;
	}
	catch(e){
		Response.Write(e.message);
		return false;
	}
}
</script>
<%
sub sub1
	dim value : value = fct1()
	response.write value
end sub

call sub1()
%>

Now, go and start converting your Classic ASP functions in JavaScript!
Just, watch out as JScript is case sensitive, VBScript is not.
vb: response.write "txt"
js: Response.Write("txt");

 

How to mix Classic ASP and Server-Side Javascript

Sometimes I need to fix some old Classic ASP applications or add small new features to them.

Because I do Javascript or C# every day for new apps, it hurts to get back to VBScript for these old apps!

That’s why I try to do these using Server-Side Javascript instead.  But wait, how can I mix NodeJS and VBScript?  The answer is, you can’t.  But, there was Server-Side JS before NodeJS exists!

Now, look at this.

You have a ASP Classic site like this:

<body>
<% dim product : product = "apple"
response.write product %>
...

And you need to create a new function to get the product name.

But, you don’t want to do it in VBScript, because you prefer JavaScript.

All you need to do is to create an “include” file, in pure javascript, like this:

includeJS.inc:

function getProduct(){
	var product = "banana";
	return product;
}

And, add it to your existing ASP file:

<script runat="server" language="javascript" src="includeJS.js" ></script>

Finally, you can fix your existing code like this:

<% dim product : product = getProduct()
response.write product %>

Yes, the VB code can call JS function directly.
Also, your JS code can also use already existing VBScript functions and variables.

(edit 2020-12-23) I just added a working sample for this, that you can download, including web.config “urlrewrite” to keep your js-code hidden from browser direct call.

IIS can run Server-Side Javascript since 1997

When I read articles about NodeJS, they almost all consider NodeJS like if Ryan Dahl invented Server-Side Javascript.

But, did you know that, in IIS 3.0 on Windows NT 4.0, it was possible to run server-side javascript?

On May 15, 1997, Microsoft released the Service Pack 3 of Windows NT4, introducing Active Server Page technology (ASP).

Classic ASP was built to run Active Script.  VBScript AND JScript are the first Active Script languages developped, and were included in all versions of Windows since 95.  And, that “Jscript”, can be used to run server-side javascript.

Wait, JScript is not JavaScript?  Yes it is. Just another name.  FireFox 1.0 run something named JavaScript 1.5, and IE6 run JScript 5.0  And, both were, in fact, ECMAScript 3.0. (more info)

That said, it means that if you still need to work with Classic ASP application, to maintain old software that can’t be rewritten, you can write some JavaScript to do that.  And, it is totally compatible with existing VBScript app!

Now, look at this sample of a 100% server-side javascript in an classic ASP file.

I’ll show you, in another article, how you can add some javascript in your existing Classic ASP / VBscript application.

How to get response headers on all jquery ajax requests

REST / Ajax querie are part of our day as a web developer.

Recently, we had to handle response headers (when communicating with Basecamp3 API).

The default jqXHR object is not very helpful to give us a beautiful list of all response headers.

There are 2 functions available:

  • getResponseHeader(key…) that returns the value of that key, but you need to know which one you need.
  • getAllResponseHeaders, that returns a “string” of all headers, in key-value pair, but all stuck in 1 big string.

Solution

So, we create something that is, on every call, parsing that string and set it in a easy-to-use object embedded to the jqXHR.

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
  jqXHR.done(function (results, responseText, jqXHR) {
    getResponseHeaders(jqXHR);
  })
}

function getResponseHeaders(jqXHR){
  jqXHR.responseHeaders = {};
  var headers = jqXHR.getAllResponseHeaders();
  headers = headers.split("\n");
  headers.forEach(function (header) {
    header = header.split(": ");
    var key = header.shift();
    if (key.length == 0) return
    // chrome60+ force lowercase, other browsers can be different
    key = key.toLowerCase(); 
    jqXHR.responseHeaders[key] = header.join(": ");
  });
}

Now, you can get, jqXHR.responseHeaders.etag value directly. (lowercase)

Because the “.done” set in ajaxPreFilter is set before the one of the caller, we can fill the responseHeaders property on all call.  And, when the caller gets its .done event executed, that third parameter, jqXHR, contains the responseHeaders already filled.

Warning

You will be able to retrieve these headers, if you do same-domain query.  For cross-domain queries, the server needs to return that header: Access-Control-Expose-Headers (more details)

How to know if a javascript object contains a property

You want to know if your javascript object contains a certain attribute. But, you tried some methods, and, because of the “undefined” value, it’s hard to differ from an undefined value, from an undefined “property”.

Let’s look at that simple example:

var obj = {
	key1: "value1",
	key2: "value2",
	key3: undefined
};

You want to know if obj contains “key4” property.
First, you try with “typeof”. But, for key3 and key 4, you get the same result:

typeof obj.key3
	"undefined"
typeof obj.key4
	"undefined"

So, what about property value?

obj.key3
	undefined
obj.key4
	undefined

The method I use is hidden in the very underused “Object” object.

Object.keys(xxx) returns an array of all properties of your object, as string.
So, you can do an indexOf that property name to know if it is contained in its definition.

Object.keys(obj).indexOf("key3")
	2
Object.keys(obj).indexOf("key4")
	-1

So, if you want to know if your property “exists” in your object:

function isDefined(obj, prop){
	return Object.keys(obj).indexOf(prop) > -1;
}

Another better alternative is to use the native hasOwnProperty inherited from Object.

The previous sample can also be:

obj.hasOwnProperty("key3") -> true
obj.hasOwnProperty("key4") -> false

How to track your server-server call in Fiddler

Telerik Fiddler is the web developer’s best friend.

It does a wonderful job of telling you why it worked, or not.  Its ability to edit and replay some requests is wonderful.  That, with Advanced REST Client, both help you accomplish your day to day job.

It tracks everything.
Almost.
Sometimes, you need to track server-to-server requests.  Example, if your app calls your back-end api, and then, your server needs to call Mandrill API to send an email to your customer.

By default, Fiddler is not tracking that request, that goes out from your server-side app. But, there’s a solution.

In fact, Fiddler track all web traffic generated by “you”, the user currently logged, and who started the fiddler app.

Now, knowing that, all you need to do, is make your IIS Pool run at your name.

By default, IIS uses “ApplicationPoolIdentity” user, it’s a kind of virtual user generated by the web engine, to run the app.  Each pool have its own username.

But, you can change it to something else.

Open IIS.  Go to the Application Pools section. Choose your app pool, then open Advanced Settings / Identity.  Click the dots, choose Custom account, enter your credentials, and you’re done!

Now, your outgoing server-side calls from your back-end can be tracked in Fiddler!

Watch out for IndexedDB + [Date] format

You may have read that post from Raymond Camden about using [Date] format object in indexedDB.

Following that advice, we used it in our application.

Everything was fine, until we got customers using IE11 on windows 7.  IE11 on win8.x, and Win10 were OK, but, only on windows 7, we had errors.

After some investigations, using the Microsoft provided Virtual Machine to test IE11 on Windows 7, we found that all our “Date” used in index, were converted to ISO String!

So, we had to change our app, and use ISO string everywhere for dates we need to use as index, just in case we got customers with Internet Explorer 11 on Windows 7.

P.S. we are using db.js, so we’re not sure if the browser itself modify our date variable to string, or db.js, but it just happen.