FYP_Final_Report_2.doc.doc

137
Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces DE3 Authors: Kou Man Tong, Fung Chak Fai 1

description

 

Transcript of FYP_Final_Report_2.doc.doc

Page 1: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

DE3

Authors: Kou Man Tong, Fung Chak Fai 1

Page 2: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Powerful AJAX Tools for Lightweight Portable Web User Interfaces

by

Kou Man Tong Fung Chak Fai

Advised by

Prof. Dekai Wu

Submitted in partial fulfillment

Of the requirement for COMP 396

in the

Department of Computer Science

Hong Kong University of Science and Technology

2006-2007

Name of Student: Signature: Date:

Name of Student: Signature: Date:

Authors: Kou Man Tong, Fung Chak Fai 2

Page 3: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Table of Contents

1 Introduction........................................................................................................5

1.1 Overview..................................................................................................5

1.2 Objectives................................................................................................5

1.3 History......................................................................................................6

1.4 Work Completed....................................................................................6

2 Object Model and Event System.................................................................13

2.1 Introduction..................................................................................................13

2.2 Circular References and Internet Explorer 6.......................................14

2.3 The Lapsed Listener Problem..................................................................24

2.4 Performance Implications.........................................................................29

2.5 The Search for Solutions..........................................................................39

2.6 Object Model of WT Toolkit.......................................................................47

2.7 Weak Reference Emulation......................................................................51

2.8 Event System................................................................................................56

3 AJAX RPC System..........................................................................................58

3.1 Using the AJAX RPC System in WT Toolkit.........................................58

3.2 The JSON Data Exchange Format..........................................................60

3.3 Using the AJAX RPC System in Web Server.......................................61

4 Regular Widgets System...............................................................................65

4.1 Introduction..................................................................................................65

4.2 The wtWidget Class....................................................................................65

4.3 Example Widget Classes...........................................................................67

5 AJAX Forms System......................................................................................69

5.1 Introduction..................................................................................................69

5.2 Using AJAX Forms in WT Toolkit............................................................69

5.3 Example Input Form...................................................................................72

6 Vector Graphical Widgets System..............................................................75

6.1 Introduction..................................................................................................75

6.2 Base Components of the Vector Graphics System............................76

6.3 Charting Engine...........................................................................................78

6.4 G=(V,E) Graph Engine................................................................................82

6.5 3D Objects.....................................................................................................83

6.6 Live Demonstrations..................................................................................83

7 Conclusions......................................................................................................86

8 References........................................................................................................88

9 Appendix A: Source Code for Finding Programming Patterns Prone

Authors: Kou Man Tong, Fung Chak Fai 3

Page 4: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

to Memory Leaks in Internet Explorer 6............................................................91

9.1 Leak Experiments with Simple Circular References.........................91

9.2 Leak Experiments with Closures............................................................95

9.3 Leak Experiment with Function Objects...............................................98

10 Appendix B: Source Code for Finding JavaScript Operations

Affected by Memory Leaks in Internet Explorer 6........................................100

11 Appendix C: Source Code for Showing JavaScript Object Creation

Latency Deteriorating with Number of Reachable JavaScript Objects

under Internet Explorer........................................................................................107

12 Appendix D: Conversations in Dojo Interest Mailing List

Regarding the Lapsed Listeners in Dojo Toolkit...........................................111

Authors: Kou Man Tong, Fung Chak Fai 4

Page 5: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

1 Introduction1.1 Overview

Web applications are taking a more and more important part in our daily

lives, and they are certainly not limited to convenience applications like

Google Maps - the use and development of web applications is penetrating

all kinds of modern institutions. For example, enterprise resource planning

systems has been implemented as web applications by major ERP vendors

since 2000 [14]; web applications are playing a crucial role in the

deployment of citywide wireless Internet projects in some cities of the

United States [18]. In HKUST, web applications, such as WebCT[12],

VELA[11], LMES[24] are playing a more and more important part in

teaching activities.

As web applications has progressed from simple HTML tables and forms to

modern rich Internet applications [32] that incorporate features and

functionalities of desktop applications, there is a great need for robust web

application development frameworks that let application developers write

web applications with the same kind of ease as developing desktop

applications. Recently, a powerful paradigm called AJAX [31]

(Asynchronous JavaScript and XML) has emerged in the web development

community that makes it possible to write rich, responsive web applications

without the use of proprietary browser plug-ins. The AJAX approach was

first popularized by Google Maps and Gmail and later adopted by many

websites and web applications such as Flickr[5], Google Docs and

Spreadsheets[13], EditGrid[26] and PCMS[16]. A significant problem with

AJAX is that many people are regarding it as something very difficult and

exotic. Some people think that AJAX is so hard that a manager from

Microsoft was quoted as saying, “People who do (AJAX development) are

rocket scientists” [15]. In this project, we are going to design and implement

an open source toolkit, called WT Toolkit, which makes it easy for

application developers to write rich AJAX-style web applications.

1.2 Objectives

The objectives of this project are the following:

Authors: Kou Man Tong, Fung Chak Fai 5

Page 6: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

1. To make AJAX RPC requests as simple as possible to the eye of a web

developer, such that he can have more time to focus on the business logic

instead of doing a lot of mechanical coding to handle browser

irregularities;

2. To build a rich and robust graphical widget library, such that web

developers using WT Toolkit can easily draw convincing user interfaces

that give users an impression that what he is using is indeed a serious

application, rather than just a web page with forms;

3. To implement a robust event handling mechanism in JavaScript, based

on the tried-and-true observer pattern often seen in desktop application

development environments;

4. To make WT Toolkit agnostic to the server side architecture.

1.3 History

WT Toolkit is an open source re-implementation of a proprietary AJAX

toolkit developed for the PCMS project (PePWave Centralized Management

System) in PePLink Ltd., an R&D oriented company headquartered in Hong

Kong. PCMS has been deployed in various city-wide wireless Internet

installations in the United States. For example, it is currently deployed in the

City of St. Cloud, Florida [18]. It is also mentioned in one of the press

releases of Tropos Networks [20], a US company specialized in citywide

Wi-Fi Internet service. One of the project team members of this project, Kou

Man Tong, is the original developer of both the PCMS system and WT

Toolkit.

1.4 Work Completed

AJAX RPC, Event System, Basic Widget Library

A signal-slot event handling system, a set of DHTML widgets, and the

AJAX RPC class (wtRemoteProcedureCall) were implemented in January

2006. These formed the base feature set of WT Toolkit and were being

incrementally improved upon during the course of the project.

A real application demo of WT Toolkit, “francium’s Xanga Tracker” [27]

was written in January 2006 and has been opened to public registration from

Authors: Kou Man Tong, Fung Chak Fai 6

Page 7: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

February 2006. It has 113 registered users as of 7th April, 2007. Some of the

registered users of “francium’s Xanga Tracker” are current Computer

Science and Computer Engineering students in HKUST. The earliest

versions of “francium’s Xanga Tacker” had a total of less than 10 lines of

HTML code – all of the client side user interface logic was implemented in

JavaScript with WT Toolkit. The server side logic was implemented in

Python. mod_python [9] was used in implementing the server side logic.

Figure 1 – Pressing the “Xanga Log” tab triggers a refresh of displayed contents. This operation

would leak more than 10MB of memory every time it is executed on the earliest versions of

francium’s Xanga Tracker.

It was discovered with the application demo that earlier versions of WT

Toolkit had a severe memory leak problem. An early user refreshing his

Xanga Log contents in “francium’s Xanga Tracker” for a few times would

see the committed memory space of his web browser increase by more than

10MB, for each time he clicked on the “Xanga Log” tab, which triggered the

refresh.

Investigations into the memory leak problem showed that two memory

management problems existed in the earliest versions of WT Toolkit. One of

them was specific to Internet Explorer 6, in which the browser’s garbage

collector was unable to determine the liveliness of objects when there exist

Authors: Kou Man Tong, Fung Chak Fai 7

Page 8: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

circular references with DOM objects. Another problem discovered was the

lapsed listener problem [25], which is a programming anti-pattern related to

primitive implementations of the observer design pattern. It was also found

that another popular open source web UI toolkit, Dojo Toolkit [6] suffers

from the lapsed listener problem.

To combat the memory management problems in WT Toolkit, weak

reference emulation logic was implemented in WT Toolkit. The weak

reference emulation logic also provided various side benefits to WT Toolkit

in addition to solving the memory leak.

The base features of WT Toolkit described above are reported in details in

Sections 2, 3 and 4 of this report.

AJAX Forms, Form Widget Library

One of the most obvious uses for AJAX RPC is to submit user inputs, and

get feedback from the web server, without refreshing the web page. An

AJAX form class, wtForm, with a set of associated form widgets was

implemented in WT Toolkit. The AJAX form system was completed in

January 2006 and was being incrementally improved upon during the course

of the project.

Similar to the AJAX RPC class, the AJAX form class and all associated

form widgets are built upon the toolkit’s signal-slot event handling system.

This gives the web developer an extra degree of flexibility in programming

input forms – for example, a web developer can use the “ValueChanged”

signal of form widgets to notify other JavaScript objects that an input’s value

has been changed.

Figure 2 - A wtSpreadsheet instance.

Since the AJAX form and the form widget library in WT Toolkit are built

Authors: Kou Man Tong, Fung Chak Fai 8

Page 9: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

upon object oriented principles, sophisticated form widgets can be inherited

and aggregated from more basic form widgets in WT Toolkit. For example,

the wtSpreadsheet object is made by inheriting from a wtDisplay object and

aggregating a number of wtPopupTextbox objects. WT Toolkit is more

advanced in this respect when compared to some other popular open source

AJAX toolkit like Dojo Toolkit. In Dojo Toolkit, AJAX form is merely a

hack to bind AJAX RPC to traditional HTML form DOM nodes [7].

Building new form widgets by aggregation and inheritance in Dojo Toolkit

would be much more difficult than in WT Toolkit.

Figure 3 - A wtSpreadsheet object is made by inheriting from a wtDisplay object and aggregating

multiple wtPopupTextbox objects.

The AJAX form system in WT Toolkit is reported in details in Section 5 of

this report.

SVG/VML Vector Graphics

Under the advice of Dr. Dekai Wu, it was discovered in April 2006 that

vector graphics can be drawn under Internet Explorer with VML [19] and

under Firefox with inline SVG [30]. Initial versions and demonstrations of

our SVG/VML module were implemented December 2006, but public

release of the code module was only available from March 2007 with the

release of WT Toolkit 0.2.1:

Authors: Kou Man Tong, Fung Chak Fai 9

Page 10: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

http://sourceforge.net/project/showfiles.php?group_id=157600&package_id=176278

Apart from being able to draw basic geometric shapes like lines, polygons,

curves, and ellipses. WT Toolkit’s SVG/VML module is capable of drawing

tangible widgets aggregated from geometric shapes. For example, WT

Toolkit has a wide variety of charting widget classes, such as the bar chart

widget class (wtBarChart), the pie chart widget classes (wtPieChart and

wtAutoPieChart), the line chart widget class (wtLineChart), the radar chart

widget class (wtRadarChart), the scatter chart widget class

(wtScatterChart), and many more.

Figure 4 - Statistical charts drawn with WT Toolkit's vector graphics system.

Another notable feature of WT Toolkit’s vector graphics system is the ability

to draw interactive G=(V,E) graphs. This made it possible for us to write a

UML class diagram editor based on WT Toolkit, as one of the application

demonstrations of WT Toolkit.

Authors: Kou Man Tong, Fung Chak Fai 10

Page 11: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 5 - UML class diagram drawn with WT Toolkit's vector graphics system. All UML class

diagrams in this report are drawn with this application demo.

The SVG/VML vector graphics system in WT Toolkit is reported in details

in Section 6 of this report.

API Documentation

An API documentation describing WT Toolkit’s entire public API was

released with WT Toolkit 0.3.0. The documentation was generated with

JSDoc [29], a documentation generator very similar to the javadoc tool

distributed with Sun Microsystem’s Java Development Kit.

WT Toolkit’s API documentation can also be accessed online, without

downloading our code package, by the following URL:

http://wt-toolkit.sourceforge.net/doc-0.3.2/

Open Source

WT Toolkit is an open source project. The entirety of our project’s source

code are released to be public and licensed under the GNU Lesser General

Public License (LGPL) [8].

Our project is hosted on SourceForge:

http://sourceforge.net/projects/wt-toolkit

Authors: Kou Man Tong, Fung Chak Fai 11

Page 12: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Packaged code releases of WT Toolkit can be found in the “Download”

section of our SourceForge website.

Our development code can be checked out from the SourceForge SVN

repository by the command (assuming you have the svn tool installed):

svn co https://wt-toolkit.svn.sourceforge.net/svnroot/wt-toolkit wt-toolkit

Authors: Kou Man Tong, Fung Chak Fai 12

Page 13: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

2 Object Model and Event System2.1 Introduction

The earliest versions of WT Toolkit did not have a comprehensive object

model – it was just a collection of code wrapped up in functions to be reused

by a programmer. This ad-hoc implementation style had some serious

deficiencies, however:

1. It leads to memory leaks, especially under Internet Explorer 6 where the

JavaScript garbage collector cannot handle circular references involving

DOM nodes.

2. It does not take advantage of built-in OOP features in JavaScript such as

prototype inheritance.

3. It made implementing the signal-slot event handling system tricky and

prone to errors.

A more comprehensive object model was implemented in WT Toolkit since

version 0.2.0 to solve the three problems above. Most of the WT Toolkit

code from 0.2.0 and above is encapsulated into classes inherited from the

toolkit’s base class, wtObject. The base class provides signal-slot event

handling and the ability to act as a proxy to memory expensive (and leak

prone) objects like DOM nodes via weak references.

In the subsections that follow from here, section 2.2 explains how memory

leaks can occur with circular references in Internet Explorer 6. Section 2.3

explains how memory leaks can occur in naïve signal-slot event handling, or

more generally, observer design pattern implementations via the lapsed

listener problem [25]. Section 2.4 explains the performance implications to

Internet Explorer 6 when there are memory leaks. Section 2.5 explains how

the project group searched for solutions for the memory leak problems

observed in early versions of WT Toolkit, and how we discovered other

popular web UI toolkits to be vulnerable to memory leaks as well. Section

2.6 explains the current object model in WT Toolkit in detail. Section 2.7

explains the weak reference emulation logic, the accompanying automatic

garbage collection logic, and a proof of correctness to our garbage collector.

Section 2.8 talks about how the event system in WT Toolkit can be used by

the web application developer.

Authors: Kou Man Tong, Fung Chak Fai 13

Page 14: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

2.2 Circular References and Internet Explorer 6While Internet Explorer is often criticized for its numerous problems with

standard compliance (e.g. poor CSS support) – a less well known, but very

significant problem with Internet Explorer 6 is memory leakage. Memory

leakage is arguably a more painful problem compared to poor standards

compliance. This is because while problems with standard compliance (e.g.

a broken CSS attribute) can be easily discovered with test cases, memory

leak problems can easily go unnoticed until the very late stages of an

application development process.

As discussed in the MSDN article, “Understanding and Solving Internet

Explorer Leak Patterns” by Microsoft [22], one of the most common causes

for memory leaks under Internet Explorer is circular referencing. The

Javascript garbage collector implemented in Internet Explorer uses reference

counting for determining the liveliness of an object. As a result, Internet

Explorer 6’s garbage collector is unable to determine a set of circular

referencing objects to be unreachable in some circumstances, even though

the set of objects is no longer used by the web application.

function createEl(i) {

var span = document.createElement("span");

span.className = "muci";

span.innerHTML = " foobar #"+i+" ";

span.onclick = function() { alert(this.innerHTML + "\n" + i); };

document.body.appendChild(span);

};

function start() {

var T1 = (new Date()).getTime(); // DEBUG.PROFILE

for (var i = 0; i < 3000; ++i)

createEl(i);

alert(((new Date()).getTime() - T1) / 1000); // DEBUG.PROFILE

};

Figure 6 - Bazon's code sample for demonstrating memory leaks in Internet Explorer 6.

Symptoms of memory leaks in Internet Explorer 6 are often encountered by

Authors: Kou Man Tong, Fung Chak Fai 14

Page 15: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

AJAX application developers. An often-cited technical article by Mihai

Bazon [2] states the following symptoms:

1. Progressively degrading performance;

2. Unbound growth of memory space occupied by iexplorer.exe;

3. The symptoms of memory leak do not disappear even after a page

refresh, or navigating to another URL.

For the purpose of making a web development toolkit, we need to

understand how circular references can be formed during application

development, and devise solutions to prevent the web developer from too

easily forming the above mentioned circular referencing patterns without

putting unreasonable burden on the web developer.

Both Microsoft’s and Bazon’s articles did not clearly describe why memory

leaks occurred, although they both pointed to circular references as the

culprit. For example, in Error: Reference source not found, Bazon claimed

that reference cycles are created inside the function createEl(), with two

edges in the reference cycle:

1. The variable “span” refers to the closure via its “onclick” attribute;

2. The closure refers back to the variable “span”.

Bazon did not specify why reference number 2 was formed, however; he

only specified and demonstrated that reference number 2 exists. In this

specific case, it is essential to understand how reference number 2 came into

existence even without the identifier “span” being referred to within the

closure, such that the appropriate preventive or mitigative measures can be

determined for plugging the corresponding memory leak hole. Does the

“span” get attached to the closure because Internet Explorer would

automatically attach every object reference it can find from the outer scope

to a closure? Does the “span” get attached simply because Internet Explorer

has determined that the “this” identifier within the closure is identical to

“span”, when the closure is assigned to “span” as its onclick attribute? The

solution for tackling this memory leak pattern could be different depending

on how Internet Explorer decided to attach the outer scope variable’s

reference to the closure.

Authors: Kou Man Tong, Fung Chak Fai 15

Page 16: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

As a result, we conducted some experiments in October 2006 to explore the

finer details of memory leaks under Internet Explorer 6.

Methodology of Experiments

While it is possible to determine whether a programming pattern is leaking

by looping it a lot of times over and observing whether iexplorer.exe’s

committed memory space increases in an unbounded way, even though we

are sure that the number of reachable objects in our Javascript program is

not increasing; this method is not perfect because it can always be argued

that the seemingly unbounded committed memory size growth is observed

only because Internet Explorer’s garbage collector has not swept away the

unreachable objects, it is no proof to the garbage collector’s inability to

determine the unreachability of objects.

Figure 7 - It is always possible to argue that the seemingly unbounded allocated memory size

growth is only observed because the garbage collector has not yet swept away the unreachable

objects, it might do so later. Graph adapted from Chapter 6 of the book “Bitter Java” by Bruce

A. Tate. [25]

Luckily, there is a more accurate open source tool for detecting memory

leaks in Internet Explorer, called Drip [28]. Drip has an important limitation,

however – it cannot detect memory leaks that are not persistent after page

refreshes, which are called “pseudo-leak” in Microsoft’s article. This

limitation can be deduced by reading Drip’s source code

(http://ieleak.svn.sourceforge.net/viewvc/ieleak/trunk/drip/). By reading the

source files MainBrowserDlg.cpp and JSHook.cpp in Drip 0.5’s source tree,

Authors: Kou Man Tong, Fung Chak Fai 16

Page 17: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

it can be deduced that the leak check button of Drip 0.5 works by

performing the following procedure:

1. When the “Show DOM Leaks” button is clicked, navigate away from the

current URL to “about:blank” to trigger a Javascript garbage collection.

2. When about:blank has completed loading, any DOM objects from the

previous page that have not been unloaded is displayed as leaked DOM

nodes.

Figure 8 - Drip 0.5 is accurate enough to detect a single DOM object being leaked.

It is obvious that DOM objects not “carried over” to the about:blank page

could not be detected by Drip as memory leaks.

void CMainBrowserDlg::OnBnClickedCheckLeaks() {

// When the leak test button is pressed, navigate to the blank document

// so that the browser will release all of its elements. Set

// m_waitingForBlankDoc to true so that the DocumentComplete event

// handler will know to check for leaks when the blank document

// finishes loading.

//

requestClosePopups();

Authors: Kou Man Tong, Fung Chak Fai 17

Page 18: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Navigate(L"about:blank");

m_waitingForBlankDoc = true;

}

Figure 9 - Code snippet from MainBrowserDlg.cpp of Drip 0.5. This function is the click event

handler for the “Show DOM Leaks” button. Notice the function changes the current URL to

“about:blank”.

For the purpose of this report, we will still call unbounded memory size

growth not persistent after page refreshes as memory leaks, because it is

possible and desirable for AJAX applications to operate without any page

refreshes at all.

Even with this limitation, Drip is good enough for this part of our

investigation, because it has been asserted in both Bazon’s and Microsoft’s

articles that memory leaks involving DOM node circular references are

persistent even after page refreshes.

With the knowledge that Drip can be used for detecting circular reference

memory leaks in Internet Explorer, we can now define an experiment

procedure for showing whether a particular programming pattern would leak

memory or not:

1. Write a simple JavaScript program with the allegedly leaky

programming pattern and embed that JavaScript program in an HTML

file.

2. Prepare one or more very similar HTML files, each with only one or two

lines of JavaScript essential to the programming pattern modified or

removed, for control experiment.

3. Load the HTML file from step 1 to Drip, and see if any memory leak is

detected.

4. Load the HTML file from step 2 to Drip, and see if any memory leak is

detected.

5. If Drip reports positive result on step 3 and negative result on step 4,

then the programming pattern is determined to leak memory in Internet

Explorer 6.

Experiment with Bazon’s Code Sample

Authors: Kou Man Tong, Fung Chak Fai 18

Page 19: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

To show that our experiment procedure works, we tried the procedure with

one of Bazon’s code samples.

Authors: Kou Man Tong, Fung Chak Fai 19

Page 20: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

<html> <head>

<title></title>

<script type="text/javascript">

function createEl(i) {

var span = document.createElement("span");

span.className = "muci";

span.innerHTML = "&nbsp;foobar #"+i+"&nbsp;";

span.onclick = function() { alert(this.innerHTML + "\n" + i); };

document.body.appendChild(span);

};

function start() {

var T1 = (new Date()).getTime(); // DEBUG.PROFILE

for (var i = 0; i < 3000; ++i)

createEl(i);

alert(((new Date()).getTime() - T1) / 1000); // DEBUG.PROFILE

};

</script>

</head>

<body>

<h1></h1>

<a href="javascript:start()">start</a>

<hr />

</body> </html>

Figure 10 - Bazon's code sample from Error: Reference source not found, embedded into HTML.

Authors: Kou Man Tong, Fung Chak Fai 20

Page 21: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

<html> <head>

<title></title>

<script type="text/javascript">

function createEl(i) {

var span = document.createElement("span");

span.className = "muci";

span.innerHTML = "&nbsp;foobar #"+i+"&nbsp;";

span.onclick = null;

document.body.appendChild(span);

};

function start() {

var T1 = (new Date()).getTime(); // DEBUG.PROFILE

for (var i = 0; i < 3000; ++i)

createEl(i);

alert(((new Date()).getTime() - T1) / 1000); // DEBUG.PROFILE

};

</script>

</head>

<body>

<h1></h1>

<a href="javascript:start()">start</a>

<hr />

</body> </html>

Figure 11 - Control experiment, with the modified code (1 line) underlined.

Since part of the alleged reference cycle in Bazon’s code sample is the

closure assigned as span’s click handler, we replaced the closure with null in

our control experiment.

Authors: Kou Man Tong, Fung Chak Fai 21

Page 22: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 12 - Drip test results of Bazon’s code sample (left) and control experiment (right).

From the screenshots above, Drip showed positive result for the code sample

and negative result for the control experiment. Therefore, we arrive at the

same conclusion as Bazon – the closure was part of the reference cycle,

which induced memory leak. Therefore, our experiment procedure worked.

Experiments for Finding Leaky Programming Patterns under

Internet Explorer 6

We designed a total of 8 experiments for determining which programming

patterns would leak in Internet Explorer 6, and which would not. We do not

believe that our list contains all possible programming patterns that would

induce memory leaks by forming circular references, but all our cases are all

very simple that we believe should provide significant insight for the

construction of WT Toolkit.

The source code for the 8 experiments can be found in Appendix A of this

report. The source code for the corresponding control experiments is not

included because it is wasteful to print out the same code samples again with

only one to two lines changed. Instead, we included instructions for

producing the control experiments in the code samples that are known to

leak, for readers who would like to reproduce our experimental results.

Authors: Kou Man Tong, Fung Chak Fai 22

Page 23: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Below is a table of our experiment results:

# Reference Description of Pattern Does it Leak?

1 Figure ?? A DOM node referring to itself via an attribute. Yes

2 Figure ?? Two DOM nodes referring to each other. Yes

3 Figure ?? A DOM node referring to itself via a Javascript

object.

Yes

4 Figure ?? Two Javascript objects referring to each other, with a

DOM node attached to one of the objects as an

indicator such that any leak can be detected via Drip.

No

5 Figure ?? Closure declared in the same scope as a DOM node,

and assigning that closure as the DOM node's

attribute.

Yes

6 Figure ?? Same as the last experiment, except that the DOM

node is put inside a Javascript object such that

identifiers inside the closure cannot be bound to the

DOM object directly.

Yes

7 Figure ?? Trying to avoid circular references via closures with

even more closures. This test case is modified from

one of the suggested solutions mentioned in Bazon's

article.

No

8 Figure ?? Making a function object by calling the Function

class constructor within the same scope of a DOM

node, and assigning the function object as a DOM

node attribute.

No

Two emerging patterns can be deduced from the experiment results above:

Hypothesis 1 - Javascript circular references in Internet Explorer 6 create

cross-page memory leaks if and only if the reference cycle includes one or

more DOM nodes in it.

Hypothesis 2 - Javascript closures in Internet Explorer 6 retain references to

all outer scope variables, even though the corresponding same-name

identifier is never written inside of the closure. It is therefore very easy to

create circular references involving DOM nodes with closures.

Authors: Kou Man Tong, Fung Chak Fai 23

Page 24: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 13– Relations between objects created in init() from our first four code samples,

illustrated as UML instance diagram. Notice that the DOM node is not involved in the reference

cycle for the fourth code sample.

Error: Reference source not found can be justified by looking at the results

from the first four code samples and comparing their source code. The first

three cases all leaks memory, but the last case does not. All four cases

contain circular references; the only difference is, for the last case, the DOM

object is not involved in the reference cycle.

Authors: Kou Man Tong, Fung Chak Fai 24

Page 25: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 14 – Relations between objects created in init() from code samples 5 and 6, illustrated as

UML instance diagram.

Hypothesis 2 can be justified by looking at the source code of code samples

number 5 and 6. Memory leak occurred in both code samples, and control

experiments confirmed that the memory leak is solely resulted from the

closures. Since the only known way for including the closure to leak

memory is by circular reference, the closure must be part of a reference

cycle. If a closure forms a part of a reference cycle, then the closure must be

referring to some other objects, otherwise no cycle can be formed. In code

samples 5 and 6, discounting the extra closure created for control experiment

(which can be removed and there would still be memory leak), the only

other object that closure “f” can refer to is “node” and “jso” respectively.

The identifiers “node” or “jso” is never written inside the closure “f”. So “f”

retains references from the outer scope even though the identifiers “node” or

“jso” was never written inside “f”. The circular reference has nothing to do

with the “this” identifier inside the closure, because the control experiment’s

closure “g” in the code sample does not leak memory.

2.3 The Lapsed Listener Problem

Authors: Kou Man Tong, Fung Chak Fai 25

Page 26: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 15 – An observer pattern implementation shown on Wikipedia, notice that the event

publisher class Ball keeps strong references to its event subscribers of the IObserver class. In

the programmer’s eyes, instances of Ball can have a very long lifecycle while instances of

IObserver can have a very short lifecycle (e.g. football players may leave and join the game, yet

the football is the same). This implementation is prone to the lapsed listener problem.

[33]

The lapsed listener problem is a common programming anti-pattern that

causes the failure to release memory occupied by objects, even though said

objects are no longer needed in the programmer’s eyes [10]. It is often the

consequence of a naïvely implemented event handling system designed upon

the observer design pattern. It does not go away even if the garbage collector

of the underlying programming language works perfectly.

“A lapsed listener is when an object is added to a collection but never

removed. The most common example of this is an event listener, where the

object is added to a listener list, but never removed once it is no longer

needed. So the object's usefulness has lapsed because although it's still in the

list, receiving events, it no longer performs any useful function.”

Figure 16 – Quote from the article “How Do You Plug Java Memory Leaks?” from the February

Authors: Kou Man Tong, Fung Chak Fai 26

Page 27: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

2000 issue of Dr. Dobbs Journal.

Not being aware of the potential danger of lapsed listeners, the signal-slot

event handling system implemented in WT Toolkit prior to version 0.2.0

leaked memory whenever the programmer forgets to disconnect the slots of

an unused object from the signals of other live objects, before that object is

left to disuse (and supposedly left to be cleaned up by the JavaScript garbage

collector). The first usable application demo written with WT Toolkit,

“francium’s Xanga Tracker” [27] showed symptoms of the lapsed listener

problem in its earliest versions. These included:

1. Unbounded growth of allocated memory space for all browsers (Firefox,

IE6, IE7), as the user refreshes his Xanga log entries.

2. A Xanga blog page being tracked by “francium’s Xanga Tracker v0.1.3”

would freeze the browser if left opened for too long (say, a few days)

and is closed.

Figure 17– Unbounded growth in allocated memory space observed with firefox.exe as the user

refreshes his Xanga Log entries repeatedly in francium’s Xanga Tracker v0.1.3.

Authors: Kou Man Tong, Fung Chak Fai 27

Page 28: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

A quick check on our Xanga Tracker’s source code found a very dangerous

lapsed listener pattern in the code concerning refreshing Xanga Log entries:

1. There are many short-lived DOM objects as the cells and rows in the

table displaying the Xanga log entries.

2. Each one of the short-lived DOM objects is subscribed to a permanent

mouse event publisher, so the mouse event publisher keeps references to

all the short-lived table cells and rows.

3. Every time the Xanga log entries are refreshed, the table cells and rows

disappear and are of no use to the programmer. However, the global

mouse event publisher is still keeping references to them and thus they

cannot be garbage collected.

It is certain that many more such lapsed listener patterns can be found by

inspecting the source code further, because all events in the Xanga Tracker

are handled by the signal-slot system (which is a kind of event handling

mechanism based on the observer pattern) implemented in WT Toolkit. It is

thus very desirable to have a general solution that can mitigate the risk of

lapsed listeners in our signal-slot event handling system.

Lapsed Listeners in JavaScript

At the first glance, it seems that lapsed listeners is purely the programmer’s

fault, and it should be the programmer’s job to solve lapsed listener

problems in his program, instead of WT Toolkit’s job. There are even

superficial parallels that one can easily draw for this argument – the “delete”

keyword in C++, the free() standard library function in C - if it is acceptable

for the programmer to free up the memory taken by an object or a variable in

two of the most popular programming languages, why would it be

unacceptable for the programmer to perform the necessary cleanup of signal-

slot connections before or after an object is left to disuse in JavaScript?

There’s even a “delete” keyword in JavaScript, it seems like talking about

lapsed listeners in JavaScript is nonsensical.

a = {"a":20, "b":30};

b = a;

a.a = 80;

delete a;

Authors: Kou Man Tong, Fung Chak Fai 28

Page 29: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

alert(b.a + "," + b.b); // The string ”80,30” appears on screen

Figure 18 – Code snippet in JavaScript. Deleting the object “a” does not erase the memory

occupied by its value because the same object reference is held by the identifier “b”.

First, the semantics of the “delete” keyword in JavaScript is different from

that in C++. In C++, “delete” means freeing up the memory held by a

pointer unconditionally – deleting a pointer that is still being held by other

objects in a C++ program would create dangling pointers, which is a

potential danger. The “delete” keyword in JavaScript, however, only means

unbinding an identifier from its value – if the value’s object reference is held

by more than one identifier, deleting just one identifier would not free up the

memory used by the value. The “delete” call in JavaScript is very much like

the unlink() system function or the rm command in Unix systems in this

respect – unlinking a file in Unix does not automatically mean the space

held by the file is freed up, because there may be other hard links bound to

the same file content.

Second, the relation between a pointer returned by malloc() or the new

operator and its allocated memory area is always one-to-one in C or C++.

The relationship between signals and slots in a signal-slot event handling

system, however, can be many-to-many. In talking about lapsed listeners in

signal-slot systems, we are mainly concerned about slots. A slot in WT

Toolkit can be connected from multiple signals at the same time, and as with

any decent observer design pattern implementation, the programmer should

not need to know how many signals are actually connected to his slot at any

moment. Therefore, requiring the programmer to disconnect each and every

signal-slot connection of an object before it is left to disuse is not always

possible.

What if we make the slots automatically aware of the signals that are

connected to it, by, say, adding an array to the slot that remembers what

signals are currently connected to it, and modifying that array in the

wtObject.connect() and wtObject.disconnect() operations? This approach

could be correct in other programming languages. Unfortunately, this

approach is not correct in JavaScript. As shown in Section 2.2 in this report,

a closure in JavaScript, under Internet Explorer at least, holds references to

all locally defined variables in its outer scope even if those variables are

Authors: Kou Man Tong, Fung Chak Fai 29

Page 30: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

never referenced in its inner scope. How is this relevant to lapsed listeners?

Look at the following pseudo-code snippet:

function foo()

{

global variable a = new wtObject();

global variable b = new wtObject();

local variable c = a;

bar1 = function(){}

bar2 = function(){}

assign bar1 as a slot in a;

assign bar2 as a slot in b;

create the signal "Sig" in a;

create the signal "Sig" in b;

connect b.Sig to a.bar1;

connect a.Sig to b.bar2;

}

foo();

disconnect all signals-slot connections connecting to and from of a;

delete a;

Figure 19 – Pseudo-code snippet showing a possible solution for the lapsed listener problem in a

signal-slot event handling system.

Assuming the above pseudo-code snippet was realized in JavaScript. In the

end of the code snippet, although we have already disconnected any signal-

slot connections connecting to and from the object “a” before leaving it to

disuse, the object “b” is still holding at least one reference to the object

reference that used to be “a”. Why? This is because one of the slot functions

of object “b” have retained implicit references back to foo()’s local variable

“c”, which holds the same object reference of the previous “a”.

Therefore, in implementing the signal-slot event handling system in WT

Toolkit, we cannot rely on the programmer being careful enough to

disconnect all incoming or outgoing signal-slot connections before leaving

an object to disuse. Because even if he is so careful, there can be still lapsed

listeners. A more aggressive solution is needed.

Authors: Kou Man Tong, Fung Chak Fai 30

Page 31: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Lapsed Listeners in Other Web UI Toolkits

It has to be noted that the lapsed listener problem is not unique to the signal-

slot event system of early WT Toolkit versions. The problem is present in

the current versions of many popular web UI toolkits. In our project, it was

found that Dojo Toolkit [6] and Yahoo! UI Library

(http://developer.yahoo.com/yui/) are both vulnerable to lapsed listeners as

of April 2007. In this aspect, it can be said that WT Toolkit’s event system is

more advanced when compared to Dojo Toolkit and Yahoo! UI Library.

More details about the vulnerabilities in Dojo Toolkit and Yahoo! UI Library

are reported in Section 2.5 of this report.

2.4 Performance ImplicationsDespite unwanted memory consumption, memory leaks in JavaScript can

have negative consequences on the latencies of operations. Some of the

consequences are expected – for example, when we have lapsed listeners in

an event system which is based on the observer design pattern, the time to

process events would rise naturally. This is because when an event is fired,

the lapsed listeners are still being notified of the event, despite the fact that

they are useless. What is interesting is that we have found some unexpected

consequences of JavaScript memory leaks in this project, specifically,

memory leaks under Internet Explorer 6.

Object Creation Latency and Internet Explorer 6 Memory Leaks

In the article “IE: Where’s my memory?” by Mihai Bazon [2], Bazon

asserted and demonstrated that the general performance of a web application

with memory leak would deteriorate incrementally under Internet Explorer

6. During the development of WT Toolkit, however, it was discovered that

Bazon’s statement is not generally true. During our investigation, it was

discovered that not all JavaScript operations were affected by memory leak

performance-wise.

For this part of our investigation, four HTML files were created, with their

embedded Javascript derived from four of the leaky Javascript programs

found in Section 2.2. Therefore, all four code samples used in this section

shows cross-page memory leaks in Internet Explorer 6.

Since we are testing for performance in this section, it is important to

mention the machines on which the experiments were performed. We

Authors: Kou Man Tong, Fung Chak Fai 31

Page 32: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

executed each of the four code samples on the two machines below:

Machine 1 – A high end desktop

Intel Core 2 Duo E6400 overclocked to 3GHz

1GB memory

Windows XP SP2 with IE6

Machine 2 – Any random machine in FYP lab

Intel Pentium 4 3.2GHz

1GB memory

Windows XP SP2 with IE6

The four code samples:

# Reference Description

1 Figure ?? Each time the link “Create 2000 DIV nodes” is clicked, 2000

self-referencing DOM nodes are created.

2 Figure ?? Each time the link “Create 2000 DIV nodes” is clicked, 1000

pairs of circular referencing DIV nodes are created.

3 Figure ?? Each time the link “Create 2000 DIV nodes” is clicked, 2000

DIV nodes each with a reference to itself via a Javascript

object is created.

4 Figure ?? Each time the “Create 2000 DIV nodes” link is clicked, 2000

DIV nodes each with a reference to itself via a closure is

created.

The operation flow of the four code samples is very similar to Bazon’s code

samples for demonstrating memory leak and deteriorating performance in

Internet Explorer 6:

1. A single link, “Create 2000 DIV nodes” appears when the HTML file is

loaded.

2. Each time the link is clicked

i. The system time is recorded as the start time.

ii. 2000 DIV nodes are added to the page by Javascript

iii. The system time is recorded as the end time.

iv. The operation latency is calculated by (end time – start time) and

displayed.

Authors: Kou Man Tong, Fung Chak Fai 32

Page 33: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

The initial experiment procedure is as follows:

1. Load one of the HTML files to Internet Explorer 6;

2. Click on the “Create 2000 DIV nodes” link;

3. Record the committed address space size of iexplorer.exe by reading the

VM size column from Task Manager;

4. Record the operation latency displayed by the code sample;

5. Refresh the page;

6. Repeat steps 2 to 5 by 10 times;

7. Repeat steps 1 to 6 until all (machine, code sample) combinations have

been tested.

No control experiment was designed initially because it was not known

which JavaScript operation would be affected by the memory leak. Control

experiments were performed after hypotheses were drawn on the affected

operations.

Authors: Kou Man Tong, Fung Chak Fai 33

Page 34: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Here are the initial experiment results:

Allocated Memory (High End Desktop)

1159613620 14960

1669218100

2021621944 23252

2498026468

1166813640

1518016916 18240

2011221836

2350825192

26724

1258815716

1816420768

2345225996

2855631336

3396436392

13520

17444

21468

24976

28896

32724

36352

39984

43820

47388

0

5000

10000

15000

20000

25000

30000

35000

40000

45000

50000

1 2 3 4 5 6 7 8 9 10

Trial

KB

ytes

Code Sample #1 Code Sample #2 Code Sample #3 Code Sample #4

Figure 20- Allocated Memory vs. Trial on High End Desktop.

Operation Latency (High End Desktop)

296 297 297 282 297 297 297 297 297 297282 281 297 297 281 297 297 297 297 297312 375 485 562 625 687 788 844 891 953

407

766

1140

1547

1891

2296

2657

3031

3422

3797

0

500

1000

1500

2000

2500

3000

3500

4000

1 2 3 4 5 6 7 8 9 10

Trial

Tim

e (m

s)

Code Sample #1 Code Sample #2 Code Sample #3 Code Sample #4

Figure 21 - Operation Latency vs. Trial on High End Desktop.

Authors: Kou Man Tong, Fung Chak Fai 34

Page 35: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Allocated Memory (FYP Lab PC)

1038412364 13924

1562017392

18952 2052822220 23784 25316

1038012352

14112 1560417268

1902820672 22180

2407225704

1134014316

1689619804

2232024808

2746430076

3293635404

12488

1660420388

24024

2785231568

3538839048

4274846404

0

5000

10000

15000

20000

25000

30000

35000

40000

45000

50000

1 2 3 4 5 6 7 8 9 10

Trial

KB

ytes

Code sample #1 Code Sample #2 Code Sample #3 Code Sample #4

Figure 22 - Allocated Memory vs. Trial on FYP Lab PC.

Operation Latency (FYP Lab PC)

625 609 593 609 609 609 625 594 610 610609 625 610 625 640 625 609 625 625 625734 875 1016 1140 1313 1437 1578 1687 1844 2031

10001640

22972922

35474156

47815406

60316704

0

1000

2000

3000

4000

5000

6000

7000

8000

1 2 3 4 5 6 7 8 9 10

Trial

Tim

e (m

s)

Code sample #1 Code Sample #2 Code Sample #3 Code Sample #4

Figure 23 - Operation Latency vs. Trial on FYP Lab PC.

Although the memory consumption graphs showed that all four test cases

leaks memory incrementally between trials, the operation latency of code

samples 1 and 2 stayed constant. This observation comes in contrary to what

Bazon claimed.

Comparing the source code of code samples 1, 2 with code samples 3, 4, one

of the significant differences between them is that JavaScript objects were

created and subsequently leaked away in circular references with DOM

nodes in code samples 3, 4, while no JavaScript objects were created with

each DOM node in code samples 1, 2. This might seem ridiculous in the first

glance, isn’t a DOM node also a JavaScript object? They are not.

Authors: Kou Man Tong, Fung Chak Fai 35

Page 36: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

So we draw the following hypothesis:

Hypothesis 3 – JavaScript object creation latency deteriorates with the

number of JavaScript objects leaked in circular references involving DOM

nodes, under Internet Explorer 6.

To verify our hypothesis, we can attach JavaScript objects to the leaked

DOM nodes in code samples 1 and 2, and see if the operation latencies

would increase or not.

So we performed control experiments with code samples 1 and 2 with a

modified placeNode() below:

function placeNode(node)

{

// place the node randomly on the page

var x = parseInt(Math.random() * 800) + "px";

var y = parseInt(50 + Math.random() * 750) + "px";

node.someAttr = new Object;

node.style.position = "absolute";

node.style.top = y;

node.style.left = x;

node.style.width = "1px";

node.style.height = "1px";

node.style.fontSize = "1px";

node.style.backgroundColor = "black";

}

Figure 24 - Modified placeNode() function that is predicted to show deteriorating performance

with memory leak. Modified code is underlined.

The control experiments were performed on the high-end desktop machine.

The results are as follows:

Authors: Kou Man Tong, Fung Chak Fai 36

Page 37: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Operation Latency (High End Desktop)

297 312 313 328 343 359391 406

437469

297 313 313343 344 359

390 406 422453

050

100150200250300350400450500

1 2 3 4 5 6 7 8 9 10

Trial

Tim

e (m

s)

Modif ied code sample #1 Modif ied code sample #2

Figure 25 – Operation Latency vs. Trial on High End Desktop, control experiment.

A slight, but obvious increasing trend in operation latency was observed in

the control experiment. This confirms our hypothesis that the creation and

subsequent leak of JavaScript objects is the real reason for the deteriorating

performance.

General JavaScript Object Creation Latencies in Internet

Explorer 6

The experiments above showed that when JavaScript objects are being

leaked away with DOM circular references, subsequent JavaScript object

creation latencies would increase. However, during the development of our

project, it was noticed that deteriorating object creation latencies can still

happen under Internet Explorer 6 even if there are no memory leaks.

We found that in Internet Explorer 6, JavaScript object creation latencies

would increase with the number of reachable JavaScript objects in the web

browser, in addition to the number of JavaScript objects leaked away with

DOM circular references. The same kind of performance deterioration is not

present in Firefox or Internet Explorer 7.

Hypothesis 4 – JavaScript object creation latency deteriorates with the

number of JavaScript objects that are still in memory, under Internet

Explorer 6.

Authors: Kou Man Tong, Fung Chak Fai 37

Page 38: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Two experiments were designed to justify our hypothesis:

# Reference Description

1 Figure ?? Demonstration code for showing JavaScript object creation

latency deteriorating with number of reachable JavaScript

Objects, under Internet Explorer 6 and 7.

2 Figure ?? Control experiment. Here, although the memory usage of

iexplorer.exe is also increasing progressively, JavaScript

object creation latency does not deteriorate because the

number of reachable JavaScript objects is not increasing.

The experiments above were designed to be fully automated. A “Run

Benchmark” link appears in the browser window once the above code

samples are loaded.

Authors: Kou Man Tong, Fung Chak Fai 38

Page 39: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 26 – Screenshot of code sample 1 running.

The program flow of code sample 1 after clicking “Run Benchmark” is as

follows:

1. Go to step 3.

2. Create 20000 JavaScript objects and store them to a global array.

3. Record the current system time as startTime.

4. Create 10000 JavaScript objects and throw them away.

5. Record the current system time as endTime.

6. Print out the time taken to create the 10000 JavaScript objects by

calculating endTime – startTime.

7. Repeat steps 2 to 6 until there are 400000 or more objects in the global

array.

Figure 27 - Screenshot of code sample 2 running.

Authors: Kou Man Tong, Fung Chak Fai 39

Page 40: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Code sample 2 is a control experiment which creates DOM nodes instead of

JavaScript objects for filling up the browser’s memory space:

1. Go to step 3.

2. Create 2000 DOM nodes and add them under document.body.

3. Record the current system time as startTime.

4. Create 10000 JavaScript objects and throw them away.

5. Record the current system time as endTime.

6. Print out the time taken to create the 10000 JavaScript objects by

calculating endTime – startTime.

7. Repeat steps 2 to 6 until there are 40000 or more DOM nodes under

document.body.

Notice that the number of “filler” DOM nodes in code sample 2 is only one

tenth the number of “filler” JavaScript objects in code sample 1. This is

because DOM nodes take considerably more memory than empty JavaScript

objects.

Object Creation Latency vs. Number of Reachable JavaScript Objects

16 62 125 187282 329 391 438 515 579 641 719 766 844 890

985 1031 1094 1156 1219 1266

47141

234344

438547

640735

860953

10461172

12651360

14691609 1672

1781 18591953

2093

0

500

1000

1500

2000

2500

020

000

4000

060

000

8000

010

0000

1200

0014

0000

1600

0018

0000

2000

0022

0000

2400

0026

0000

2800

0030

0000

3200

0034

0000

3600

0038

0000

4000

00

No. of Reachable JavaScript Objects

Tim

e(m

s)

Code sample 1@High End Desktop Code sample 2@FYP Lab PC

Figure 28 – Experiment with code sample 1 shows increasing object creation latency with the

number of reachable JavaScript objects.

Authors: Kou Man Tong, Fung Chak Fai 40

Page 41: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Object Creation Latency vs. Number of DOM Nodes

15 16 15 15 16 15 15 15 15 16 16 15 15 15 16 16 16 16 15 16 16

47

31 31 31 31 31

47

32 32 31 32 31 31 32 31 31 31 31 31 32 31

05

101520253035404550

020

0040

0060

0080

00

1000

0

1200

0

1400

0

1600

0

1800

0

2000

0

2200

0

2400

0

2600

0

2800

0

3000

0

3200

0

3400

0

3600

0

3800

0

4000

0

No. of DOM Nodes

Tim

e (m

s)

Code sample 2@High End Desktop Code sample 2@FYP Lab PC

Figure 29 - Control experiment (code sample 2) with DOM nodes instead of JavaScript objects

that are stored in the memory.

The experimental results above showed that, under Internet Explorer 6,

JavaScript object creation latencies increases with the number of reachable

JavaScript objects, but not other factors that would also increase memory

usage (like number of DOM nodes in the current web page).

2.5 The Search for SolutionsWe tried to find solutions to the memory leak problems we discovered by

first looking at how other popular client side Web UI toolkits approached

them, and failing that, we looked for solutions in other programming

languages.

Case Study 1: Dojo Toolkit

We studied Dojo Toolkit first, because from reading one of the Alex

Russell’s (Project founder of Dojo Toolkit) blog entries [23], it seems that he

was very well aware of the memory leak problems and he had already

implemented a reasonable solution.

Actually writing test cases for Dojo Toolkit, unfortunately, turned up with

the same symptoms of lapsed listeners as WT Toolkit does. Two code

samples were written for experimentation:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

Authors: Kou Man Tong, Fung Chak Fai 41

Page 42: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<title>Dojo Button Widget Test</title>

<script type="text/javascript" src="dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.Button");

</script>

</head>

<body>

<script type="text/javascript">

var widgetArray = [];

function createOne()

{

var widget = dojo.widget.createWidget("Button", {"caption":"Hi!"});

var node = widget.domNode;

node.style.position = "absolute";

node.style.top = parseInt(Math.random() * 800) + "px";

node.style.left = parseInt(Math.random() * 800) + "px";

dojo.body().appendChild(node);

widgetArray.push(widget);

}

function destroyAll()

{

while(widgetArray.length > 0)

{

var widget = widgetArray[0];

var node = widget.domNode;

widgetArray.splice(0,1);

node.parentNode.removeChild(node);

dojo.event.browser.clean(node);

}

}

function createMany()

{

for(var i=0;i<100;i++)

Authors: Kou Man Tong, Fung Chak Fai 42

Page 43: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

createOne();

}

</script>

<a href="javascript: createMany();">Create 100 buttons</a>

<br>

<a href="javascript: destroyAll();">Destory all</a>

</body>

</html>

Figure 30 – First code sample for testing Dojo Toolkit. Here, 100 buttons are created each time

the “Create 100 buttons” link is clicked, and all of the are destroyed when the “Destroy All” link

is clicked.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<title>Dojo Button Widget Test</title>

<script type="text/javascript" src="dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.Button");

</script>

</head>

<body>

<script type="text/javascript">

var widgetArray = [];

function createOne()

{

var node = document.createElement("div");

node.innerHTML = "Hello World!";

node.style.position = "absolute";

node.style.top = parseInt((100 + Math.random() * 800)) + "px";

node.style.left = parseInt(Math.random() * 800) + "px";

document.body.appendChild(node);

Authors: Kou Man Tong, Fung Chak Fai 43

Page 44: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

widgetArray.push(node);

var clickHandler = function()

{

alert("Hello there!");

}

dojo.event.connect(node, "onclick", clickHandler);

}

function destroyAll()

{

while(widgetArray.length > 0)

{

var node = widgetArray[0];

widgetArray.splice(0,1);

node.parentNode.removeChild(node);

dojo.event.browser.clean(node);

}

}

function createMany()

{

for(var i=0;i<200;i++)

createOne();

}

</script>

<a href="javascript: createMany();">Create 200 messages</a>

<br>

<a href="javascript: destroyAll();">Destory all</a>

</body>

</html>

Figure 31 - Second code sample for testing Dojo Toolkit. Here, 200 DIV nodes are created each

time the “Create 200 messages” link is clicked, and all of them are destroyed when the “Destroy

all” link is clicked.

Authors: Kou Man Tong, Fung Chak Fai 44

Page 45: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Here is the experimental procedure for the above two code samples:

1. Place the two HTML files at the root of the source tree of Dojo 0.4.1;

2. Load the two HTML files to any browser;

3. Click the “Create …” link;

4. Click the “Destroy all” link;

5. Repeat 3 and 4 for an arbitrary number of times, and observe the VM

Size of the browser process in Windows Task Manager.

The first code sample tests Dojo Toolkit’s widget system by creating Dojo-

specific widgets, while the second code sample test Dojo Toolkit’s event

handling system by using the signal-slot event handling mechanism in Dojo

Toolkit. Assuming Dojo Toolkit’s widget system and event handling system

are immune to the lapsed listener problem, the observed VM Size in step 5

of the experiment procedure should not show a trend of unbounded growth.

Unfortunately, unbounded committed address space growth was exactly

what happened when we conducted the experiment.

A video was captured and posted to YouTube for demonstrating the

unbounded growth of committed address space of the test cases under

Internet Explorer 6. It can also be observed from the video that the latency

of creating the 200 DIV nodes in the video was deteriorating as steps 3 and 4

of the experiment procedure were repeated:

http://www.youtube.com/watch?v=DVcUidSRoLQ

The issue was raised in the Dojo Toolkit Interest mailing list in January 2007

(http://dojotoolkit.org/pipermail/dojo-interest/2007-January/thread.html). A

lot of people responded to our question, including Alex Russell. We got third

party confirmations of the problem from the mailing list, and Alex’s answer

was that the development team of Dojo Toolkit was already preoccupied

with the Internet Explorer 6 specific memory leaks discussed in Section 2.2

of this report, and memory leaks resulted from the lapsed listener problem

was not their priority.

The original question, and a few interesting replies to our question on the

Dojo Interest mailing list are included in Appendix D.

Case Study 2: Yahoo! UI Toolkit

Yahoo! UI Toolkit included two functions purgeElement() and

Authors: Kou Man Tong, Fung Chak Fai 45

Page 46: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

removeListener() under the package YAHOO.util.Event for unlinking event

subscribers from an event publisher. We wrote a simple test case to see if

purgeElement() worked:

<html>

<head>

<script type="text/javascript" src="build/yahoo/yahoo-min.js"></script>

<script type="text/javascript" src="build/event/event-min.js"></script>

<script type="text/javascript" src="build/dom/dom-min.js"></script>

<script type="text/javascript" src="build/dragdrop/dragdrop-min.js"></script>

<script type="text/javascript" src="build/logger/logger-min.js"></script>

<script language="javascript">

var widgetArray = [];

function createOne()

{

var node = document.createElement("div");

node.style.position = "absolute";

node.style.left = parseInt(Math.random() * 800) + "px";

node.style.top = parseInt(Math.random() * 800) + "px";

node.innerHTML = "Hello World!";

document.body.appendChild(node);

widgetArray.push(node);

var handler = function()

{

alert("Hi there!");

}

YAHOO.util.Event.addListener(node, "click", handler);

}

function createMany()

{

for(var i=0;i<200;i++)

createOne();

}

Authors: Kou Man Tong, Fung Chak Fai 46

Page 47: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

function destroyAll()

{

while(widgetArray.length > 0)

{

document.body.removeChild(widgetArray[0]);

// Yahoo UI library's implementation would leak memory if we don't purge

// every node's event handlers when we detach the nodes from the document

// tree

YAHOO.util.Event.purgeElement(widgetArray[0]);

widgetArray.splice(0,1);

}

}

function init()

{

// nothing to init here now... maybe add the logger window

}

</script>

</head>

<body onload="init()">

<a href="javascript: createMany()">Create 200 messages</a>

<br>

<a href="javascript: destroyAll()">Destroy all</a>

</body>

</html>

Figure 32 – Test case for finding if Yahoo! UI Toolkit would leak memory via lapsed listeners

when YAHOO.util.Event.purgeElement() is used for cleanup.

The experiment procedure for the above code sample is the same as the

experiment with Dojo Toolkit, except that we have to place the HTML file to

the root of Yahoo! UI Toolkit’s source tree this time.

No trend of unbounded allocated memory size growth was observed from

the above code sample. Removing the YAHOO.util.Event.purgeElement(…)

line from the function destroyAll() above would make the code sample leak

Authors: Kou Man Tong, Fung Chak Fai 47

Page 48: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

memory again. So for this case, Yahoo! UI Toolkit does not suffer from

memory leak due to lapsed listeners as long as the web developer is careful

enough to unlink all short-lived objects from longer-lived event publisher

objects when the short-lived objects are no longer needed.

However, it was already shown in Section 2.3 of this report that, even

including a function that would automatically disconnect all incoming and

outgoing observer connections, and assuming the web developer is careful

enough to remember calling that automatic function before leaving objects

into disuse, lapsed listeners can still appear in JavaScript. Therefore, while

Yahoo! UI Toolkit’s solution might work correctly in most circumstances,

there are still some cases where it would not work. Therefore, the solution

implemented in Yahoo! UI Toolkit is not a complete solution.

Case Study 3: Java

We found a chapter in the book Bitter Java [25] which is dedicated to

discussing lapsed listeners and solutions to mitigate the effects of lapsed

listeners. It mentioned three general solutions to the lapsed listener problem.

“Solution 1: Explicitly remove the listeners”

“Solution 2: Shorten the life cycle of the anchor”

“Solution 3: Weaken the reference”Figure 33 – The three general solutions to the lapsed listener problem suggested by the book

Bitter Java.

Yahoo! UI Toolkit’s solution matches the first solution, but there are cases

where it wouldn’t work in JavaScript.

The Bitter Java textbook does not recommend the second solution, although

it is listed.

This leaves us with the third solution – trying to emulate weak references in

JavaScript to mitigate memory leaks caused by lapsed listeners. Weak

references can also be used to replace strong references in circular

references among DOM nodes, so that we can still have circular references

without confusing the garbage collector in Internet Explorer 6. It has to be

Authors: Kou Man Tong, Fung Chak Fai 48

Page 49: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

noted that, while weak references can reduce memory leaks by a large

margin, it cannot truly eliminate memory leaks if the developer is extremely

careless. The reason is even the weak references themselves take up some

memory. Therefore, the third solution has to be implemented along with the

first solution for WT Toolkit.

Authors: Kou Man Tong, Fung Chak Fai 49

Page 50: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

2.6 Object Model of WT Toolkit

Figure 34 - Diagram of the wtObject class, which is the base class of all nontrivial classes in WT

Toolkit.

From version 0.2.0 and on, WT Toolkit has an object model where all

nontrivial classes inherit from the base class wtObject. There are three main

goals in designing the wtObject base class:

1. It does not leak memory, or leaks far less than what would be possible if

raw DOM node references were used instead, as long as the programmer

follows a few very trivial rules.

2. It does provide a unified interface for signal-slot event handling.

3. It allows object oriented development based on JavaScript prototype

inheritance, even for visible widget classes.

The wtObject class includes a set of operations that is common to all its

subclasses. These operations serve four main purposes: event handling,

managing weak references, accessing attributes stored in the expensive

object, and garbage collection.

Name Function

Authors: Kou Man Tong, Fung Chak Fai 50

Page 51: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

connect() Connects a signal of this wtObject to a slot of another wtObject.

disconnect() Disconnects a signal of this wtObject from a slot of another

wtObject.

emit() Emits a signal, notifies all the slots connected to this signal.

setSignal() Creates a signal for this object.

setSlot() Creates a slot for this object.

removeSignal() Removes a signal in this object.

removeSlot() Removes a slot in this object.

startProxy() Establishes a weak reference to a foreign object.

endProxy() Detaches the foreign object weak reference.

set() Sets an attribute in the foreign object.

get() Tells an attribute value in the foreign object.

addDependency() Establishes a dependency relation of this wtObject to another

wtObject. If the wtObject being depended on no longer refers to a

foreign object, then the foreign object corresponding to this

wtObject will be deleted.

Figure 35 – The default operations of a wtObject.

A wtObject is a low memory footprint proxy to a more expensive object,

which may be prone to causing memory leaks in circular references or as

lapsed listeners. For example, it might be a proxy to a DOM node. In the

absence of an expensive object, a wtObject can also proxy itself.

The proxy relation between a wtObject and its corresponding expensive

object (e.g. a DOM node) is maintained by a weak reference in the wtObject.

The weak reference is actually just a random string, which can be used find

back the expensive object from a global lookup table. This string reference is

weak because unlike strong references which we use usually, the string

reference does not protect the object that is being referred to from garbage

collection (It does protect that object from being deleted by WT Toolkit’s

garbage collector, however. This will be explained in Section 2.7). It allows

you to “refer to an object without keeping it from being collected”

(http://java.sun.com/developer/technicalArticles/ALT/RefObj/). When used

properly, having weak references can completely avoid memory leaking

circular references, which we encountered in Section 2.2. It can also be used

avoid or mitigate memory leaks caused by lapsed listeners.

Authors: Kou Man Tong, Fung Chak Fai 51

Page 52: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

In our object model, all normal attributes, event listeners (which are stored

in the wtSignals collection) and event handling functions (which are stored

in the wtSlots collection) are stored in the expensive object, instead of inside

the wtObject directly. This arrangement is used to break strong circular

references which would confuse the garbage collector in Internet Explorer 6.

It also makes the memory footprint of a wtObject very small, such that even

if it becomes temporarily a lapsed listener in some other wtObject’s wtSignal

collection, it would not occupy a lot of memory before it is cleaned up. The

only attribute that is held by the wtObject itself (and not the expensive

object) is the weak reference string, wtObjId.

Hypothesis 5 – Strong circular references with wtObjects are impossible in

WT Toolkit as long as the programmer use wtObject instance references as

attribute values, and never use the expensive object references as attribute

values.

Figure 36 - Two visible widgets, each weakly referencing a DOM Node, with an attribute pointing

to each other. Compare this graph with Figure 13 in Section 2.2, there are no strong circular

references in this graph, so this does not confuse Internet Explorer 6's garbage collector.

Hypothesis 5 is trivial to prove, and it can be visualized in a diagram like

Figure 36. As long as the programmer always uses wtObject proxies in place

of their corresponding expensive object as attribute values, there will be

always at least one weak reference in any reference cycle. Thus, strong

circular references can not be formed.

An exception to hypothesis 5 is when a wtObject is acting as a proxy to

itself. In this case, strong circular references are possible. However, as

demonstrated in Section 2.2 in this report, strong circular references

involving only JavaScript objects do not leak memory under Internet

Authors: Kou Man Tong, Fung Chak Fai 52

Page 53: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Explorer 6, so this special case is not important when memory leak is

concerned.

In the discussion that follows, it is assumed that the programmer does not

keep any long lived strong references to the expensive objects. Examples of

such strong references include assigning the expensive objects’ references as

attributes to other objects, keeping a JavaScript identifier with an expensive

object’s strong reference as it value outside a long lived closure, etc. It is

essential that a programmer using WT Toolkit avoid the above practices.

As an event listener, a wtObject is said to be lapsed if it no longer maintains

a weak reference to an expensive object. Having the weak reference gives us

one simple criterion for determining whether a wtObject is lapsed or not,

because in the absence of a weak reference, the wtObject’s event handling

slots would no longer be accessible, and the wtObject would obviously be

useless as an event listener. The signal-slot event handling logic built into

WT Toolkit can thus automatically remove lapsed event listeners based on

this simple decision criterion.

Figure 37 – The existence of the weak reference link gives us a simple criterion for deciding

whether an event listener has lapsed. In comparison, if we use the expensive object directly as

an event listener (this may be a DOM node, an XMLHttpRequest object, an ActiveX object, an

SVG matrix, among many other things), there is no simple way of determining whether that

object is still useful or not.

Therefore, when a programmer has determined that a wtObject is no longer

useful, all he has to do is to simply disconnect the wtObject’s weak

reference. Having the wtSignals collections disconnected from the wtObject,

the wtObject can no longer emit signals; having the wtSlots collections

Authors: Kou Man Tong, Fung Chak Fai 53

Page 54: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

disconnected from the wtObject, the wtObject can no longer handle events;

when some event is fired and the wtObject is still in that event’s listener

collection, the event handling logic of WT Toolkit will automatically

determine that the wtObject has lapsed, and remove it from the listener

collection. In the next time the same event is fired, the lapsed wtObject will

no longer be in the listener collection, and so the event processing latency is

not increased. Due to the fact that wtObject’s memory footprint is very

small, during the temporary state where the lapsed wtObject is still inside

some other object’s wtSignals collection, memory consumption is not

increased significantly compared to without the wtObject. Therefore the

wtObject does not pose a threat as a lapsed listener.

Moreover, we have also considered the case in which when one wtObject

has lapsed, it would lead to many other wtObjects to become lapsed. For

example, consider a wtObject which functions as a popup menu (we have

implemented this as the wtPopupMenu class in WT Toolkit). The popup

menu depends on another visible widget, for example, a button. This is

because if the visible widget from which the popup menu pops up no longer

exists, the popup menu would no longer be useful. Therefore, we allow each

wtObject to be dependent on at most one other wtObject. If a wtObject’s

depended object has lapsed, the wtObject itself would become lapsed as

well, and it will no longer maintain its weak reference to the expensive

object. This functionality is implemented as the addDependency() operation

of the wtObject class.

2.7 Weak Reference EmulationSince JavaScript provides no built-in weak references, we had to emulate

weak reference with strings and a global lookup table. Every active wtObject

holds a string key to the global lookup table, where the string key can be

used to lookup the corresponding expensive object.

Simply moving all the expensive objects into a lookup table, however, is just

like to moving all the lapsed listeners to a lookup table, and that does not

solve the problem. This is because the lookup table retains strong references

to the expensive objects. Without some algorithm to remove the expensive

objects and their corresponding weak references at the appropriate time, the

expensive objects will live beyond the time when they still useful, and

Authors: Kou Man Tong, Fung Chak Fai 54

Page 55: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

become lapsed.

The only way available to the web developer in WT Toolkit for adding

entries to the global lookup table is by calling the startProxy() method of a

wtObject instance; and the only way a web developer can explicitly remove

an entry in the lookup table is by calling the endProxy() method of a

wtObject instance. This works a lot like new and delete in C++. Compared to

the delete keyword in JavaScript, calling endProxy()actually removes the

expensive object because the global lookup table retains the only strong

reference to it. An exception to this rule is DOM nodes which are typically

tied to visible widget classes in WT Toolkit. A DOM node can have another

strong reference linking to it from the document tree. We have taken care of

this exception in WT Toolkit by including a removeSelf() operation to the

wtWidget and wtVectorWidget visible widget base classes, which removes

the DOM node from the document tree as well.

While our implementation is already correct in the sense that the

programmer has a way to reliably remove expensive objects in WT Toolkit –

unlike in Dojo Toolkit and Yahoo! UI Toolkit where the expensive objects

can become lapsed indefinitely – having the programmer call endProxy() or

removeSelf() every time he needs to remove an object is still inconvenient

and awkward in JavaScript. After all, JavaScript is a garbage collected

programming language.

When the programmer forgets to call endProxy() or the equivalent method

before leaving a wtObject instance to disuse, the wtObject instance becomes

lapsed. The essence of a lapsed listener problem is not about whether the

object is reachable or not, but rather about whether the object is still useful

or not. WT Toolkit is a GUI toolkit, so much of classes implemented in WT

Toolkit are visible widgets. Visible widgets on a browser window are always

DOM nodes, a DOM node not connected to the main document tree is never

visible and cannot fire events (e.g. there is no way you can click on

something not displayed). So in a sense, a DOM node not attached to the

main document tree is not useful.

Hypothesis 6 – A visible widget whose corresponding DOM node stays

disconnected from the document tree forever, is useless, and thus it is lapsed.

Authors: Kou Man Tong, Fung Chak Fai 55

Page 56: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Hypothesis 6 is obvious, if I can’t and I won’t see the visible widget ever,

then it is not useful.

When we are making application demonstrations for WT Toolkit, we found

that visible widgets are often rendered not useful when an ancestor DOM

node becomes detached from the document tree, usually from the result of a

removeSelf() call of its corresponding visible widget. While it is possible to

run a depth first search or breadth first search across all DOM node children

and call removeSelf() in a recursive manner to remove the lapsed DOM

nodes from WT Toolkit’s global lookup table, this approach assumes that the

whole web application UI is written with WT Toolkit, and is not correct in

all cases. What if the web developer only uses WT Toolkit in a part of his

web application UI, say, in a DIV cell placed at the upper right corner of the

browser window, and uses the DOM removeChild() call to remove that DIV

node and leaves it to disuse? In this case, all the WT Toolkit widget

instances were rendered useless, but the DFS or BFS in the widget class’s

removeSelf() operation would be useless in cleaning up lapsed objects

because it was never called.

The DOM nodes we just discussed – who became detached from the

document tree because some of its ancestors were disconnected from the

document tree – match the description in Hypothesis 6, and are useless.

They should be automatically cleaned up as well, because it is unreasonable

for the programmer clean up all the DOM child nodes manually every time

he removes a visible widget or removes a DOM node from the document

tree. Therefore, an automatic algorithm is implemented in WT Toolkit to

clean up the lapsed DOM nodes from the global lookup table. Otherwise,

WT Toolkit would leak memory. For convenience, we shall refer to the

automatic clean up algorithm as WT Toolkit’s garbage collector. Notice that

this is not the same garbage collector as the JavaScript collector built into

the web browser, our garbage collector serves only to clean up lapsed

objects from the global lookup table.

WT Toolkit’s garbage collector is a stop the world, mark and sweep garbage

collector. It is meant to be called automatically by WT Toolkit – the web

developer does not need to call it manually. It cleans up weak references and

the corresponding expensive objects from the global lookup table if the

expensive objects are determined to be lapsed. The garbage collector works

Authors: Kou Man Tong, Fung Chak Fai 56

Page 57: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

as follows:

Mark phase:

1. Create a disjoint set forest, and create a disjoint set with

document.documentElement as its only element. Call this the root set.

2. For each object in the global lookup table:

2.1. If the object does not depend on another wtObject, and it is a DOM

node, look for the closest ancestor in the DOM tree which either

has a wtObject proxy or is document.documentElement:

2.1.1.If such an ancestor is found, union the current object with that.

2.1.2.If such an ancestor is not found, no nothing.

2.2. Else, if the object depends on another wtObject:

2.2.1.Union the current object with the object that it depends on.

2.3. Else:

2.3.1.Union the current object with the root set.

Sweep phase:

1. For each object in the global lookup table:

1.1. Find the set that the object belongs to. If the object does not belong

to the root set, remove it from global lookup table and remove the

weak reference in its wtObject proxy.

Figure 38 - Algorithm of WT Toolkit's garbage collector.

The disjoint set data structure used in the above algorithm is based on the

one described in Chapter 21 of the Introduction to Algorithms textbook [3],

with union-by-rank and path compression optimizations. As a result, each

union and find operation has an asymptotic running time that grows much

slower than O(log n) and each create element or create set operation takes

O(1) on most web browsers, with the exception of Internet Explorer 6 in

which object creation latency was observed to be non-constant.

Hypothesis 7 – After the garbage collector is executed, all DOM nodes that

are not attached to the document tree, has no dependency, and whose

ancestors have no dependencies, are removed from the global lookup table.

Hypothesis 7 is true because at the end of the mark phase, there is no way

for the said DOM nodes to be in the root set. Any elements not belonging to

Authors: Kou Man Tong, Fung Chak Fai 57

Page 58: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

the root set are removed at the sweep phase. This property is useful for

removing widgets whose corresponding DOM nodes that are no longer in

the DOM tree.

Hypothesis 8 – After the garbage collector is executed, all DOM nodes that

have no dependency, and have a DOM tree ancestor with a dependency that

does not belong to the root set, are removed.

Hypothesis 8 is true because at the end of the mark phase, said DOM nodes

would belong to the same set as the depended object of the closest DOM tree

ancestor with a dependency. If that set is not the root set, all elements in that

set, including the DOM nodes, would be removed at the sweep phase. This

property is useful for removing widgets whose usefulness does not depend

on whether they are in the DOM tree or not, but whether another object is

lapsed or not. An example for this is a popup menu.

Hypothesis 9 – After the garbage collector is executed, all DOM nodes that

have a dependency not belonging to the root set are removed.

The proof and application for hypothesis 9 is the same as hypothesis 8.

Hypothesis 10 – All DOM nodes whose depended object, or the depended

object of its closest ancestor (whichever that is closer) belongs to the root

set, are not removed.

This is true because said DOM nodes would belong to the root set as well at

the end of the mark phase. The sweep phase does not remove objects in the

root set.

Hypothesis 11 – All DOM nodes that are inside the document tree, that have

no depended object, and whose ancestors have no dependencies, are not

removed.

This is true because at the end of the mark phase, they will belong to the

same set as the DOM node document.documentElement, which is the root

node of the document tree, and belongs to our root set. Hypotheses 10 and

11 make sure those DOM nodes that are still displayed or are marked as

“useful” by the programmer via addDependency() are not removed.

Authors: Kou Man Tong, Fung Chak Fai 58

Page 59: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Hypothesis 12 – All objects that are not DOM nodes, and has no

dependency, are not removed.

This is true because they are merged with the root set at step 2.3.1 of the

mark phase. There is no way for WT Toolkit to automatically determine

whether they are still useful or not. Such objects must be removed by the

programmer by calling endProxy() at the appropriate time. For example, this

can be an AJAX RPC object (i.e. a wtRemoteProcedureCall instance) that is

not related to any visible widgets of a web application.

Hypothesis 13 – All objects that are not DOM nodes and has a dependency

that belongs to the root set, are not removed.

Hypothesis 14 – All objects that are not DOM nodes and has a dependency

that does not belong to the root set, are removed.

Hypotheses 13 and 14 are true because the object would belong to the same

set as their depended object. This property is useful when the usefulness of

an object depends on whether some other objects have lapsed. For example,

an AJAX form (i.e. a wtForm instance) is usually dependent on a visible

widget on which the user can do data input. If that visible widget is

removed, then the AJAX form should be removed as well.

2.8 Event SystemThe event system implemented in WT Toolkit is modeled after the signal-

slot system in Qt (http://doc.trolltech.com/4.2/signalsandslots.html). In WT

Toolkit, each wtObject instance is allowed to have an arbitrary number of

signals and slots. A signal is just a name that represents a type of event that

the wtObject instance can fire. Signals can be created by the setSignal()

operation of the wtObject class, for example:

// fpsPlayer1 is a wtObject with an active weak reference

fpsPlayer1.setSignal(“Hit”);

Figure 39 - Creating a signal in a wtObject instance.

Authors: Kou Man Tong, Fung Chak Fai 59

Page 60: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

When a wtObject instance fires an event, it is said to emit a signal, which is

the same terminology used in Qt’s documentation. A signal can be emitted as

an argument which tells the event listeners more information about the event

that has happened.

// fpsPlayer1 has hit fpsPlayer2 in the head

fpsPlayer1.emit(“Hit”, {“who”: “fpsPlayer2”, “where”: “in the head”});

Figure 40 – Emitting a signal with an argument in WT Toolkit.

A slot in WT Toolkit is a named function in a wtObject instance that is

dedicated to handling events. The function receives 3 arguments: the first

one is the object that received the event, the second one is the event

arguments that was sent with emit(), the third one is the object that emitted

the signal. A slot can be created by the setSlot() operation of the wtObject

class.

var announceSlot = function(myself, evt, source)

{

// source is an FPS Player, with a getName() operation

var name = source.getName();

alert(name + " has hit " + evt.who + " " + evt.where + "!");

}

// gameAnnouncer is a wtObject with an active weak reference

gameAnnouncer.setSlot("Announce", announceSlot);

Figure 41 - Creating a slot in a wtObject instance.

To assign a slot as an event handler to a signal, use the connect() operation

with the signal emitter as the subject. The connect() operation takes four

arguments: the first one is the connection identifier, which can be any string

of the programmer’s choice. The connection identifier can be used to

disconnect a signal-slot pair when the programmer no longer wants the slots

to be notified of the event. The second one is the signal name. The third one

is the object holding the slot, and the fourth argument is the slot’s name.

// Assign gameAnnouncer’s Announce slot as an event listener of

// fpsPlayer1’s Hit event

fpsPlayer1.connect("conn_id", "Hit", gameAnnouncer, "Announce");

Authors: Kou Man Tong, Fung Chak Fai 60

Page 61: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 42 - Connecting a signal to a slot.

When a signal is fired, WT Toolkit’s event system guarantees that all

connected slots that have not lapsed are notified of the event. For example,

when the “Hit” signal of fpsPlayer1 is emitted as shown in Figure 40, the

application user would see the following:

Figure 43 - gameAnnounce's "Announce" slot is notified when the "Hit" signal is emitted.

3 AJAX RPC System3.1 Using the AJAX RPC System in WT Toolkit

A large part of AJAX is about sending and receiving data objects to and

from the web server without refreshing the page. Without a toolkit like Dojo

Toolkit or WT Toolkit to help in the process, this is usually accomplished

with the XMLHttpRequest object. The XMLHttpRequest object, however, is

very difficult to use. For example, the method of creating an

XMLHttpRequest object is different on different browsers

(http://developer.apple.com/internet/webcontent/xmlhttpreq.html). Another

deficiency of the XMLHttpRequest object is that it does not include a data

serialization service, so if the programmer wants to send anything more

complicated than a simple string to the web server, he will have to find a

way to serialize the data before sending it out.

Figure 44 - Public operations and attributes of the wtRemoteProcedureCall class.

Authors: Kou Man Tong, Fung Chak Fai 61

Page 62: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

WT Toolkit includes a class dedicated to handling AJAX-style RPCs, called

wtRemoteProcedureCall. This class provides a few services that makes

using AJAX RPCs much easier than using the raw XMLHttpRequest object:

1. It provides a simple and unified interface that works the same across

different web browsers.

2. It automatically serializes outgoing data and de-serializes incoming data

to and from JSON format.

3. It fires a “Success” or “Failure” event after an RPC request is submitted

to the web server. Event handlers can be programmed by WT Toolkit’s

signal-slot system explained in Section 2.8, or by calling the

setFailureHandler() and setSuccessHandler() operations with the event

handling function as a shorthand.

The wtRemoteProcedureCall constructor takes three arguments: the URL,

the RPC call name, and the data object. The data object is typically a

JavaScript object containing strings, numbers, arrays and more JavaScript

objects. Non-primitive data types can be serialized as long as it has a

toString() operation. However, WT Toolkit can not de-serialize a JSON

strings received from the web server into non-primitive data types. So, if

exchanging non-primitive data types is needed, the web developer still has to

write some custom object conversion logic.

var rpc = new wtRemoteProcedureCall(“cgi-bin/sayhello.pl”, “SayHello”, {“fromWho”: “Martin”, “toWho”:

Marco, “time”: “20070416”, “payload”:

{“question”: “when are you going to finish the XOOPS portal in our project site?”}});

Figure 45 - Creating an AJAX RPC object in WT Toolkit.

Sending the RPC request to web server can be accomplished by calling the

submit() operation.

rpc.submit();

Figure 46 - Sending the RPC request to server.

An RPC request can be either successful or a failure. A “Failure” signal is

emitted if any of the following occurs:

Authors: Kou Man Tong, Fung Chak Fai 62

Page 63: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

1. A socket error is encountered.

2. The web server returns with an HTTP status code that is not 200.

3. The web server does not respond within 5 seconds.

On the other hand, if the web server responds within 5 seconds after a

submit() call, with a HTTP status of “200 OK”, a “Success” signal is

emitted.

When a “Success” signal is emitted, the de-serialized data object is passed to

all event listeners as the event’s argument. When a “Failure” signal is

emitted, the HTTP status code (if available) or 0 (if no status code) is the

event’s argument.

var rpc = new wtRemoteProcedureCall(“cgi-bin/sayhello.pl”, “SayHello”, {“fromWho”: “Martin”, “toWho”:

Marco, “time”: “20070416”, “payload”:

{“question”: “when are you going to finish the XOOPS portal in our project site?”}});

var successHandler = function(myself, evt, source)

{

// suppose the web server sent us JavaScript object with a single field "ack"

alert(evt.ack);

}

rpc.setSuccessHandler(successHandler);

rpc.submit();

Figure 47 - Setting up and sending an RPC request with a success handler.

Figure 48 - What appears on the screen if the server sends back the string "Never!" as the "ack"

field of the returned JavaScript object.

The submitExclude attribute is a lookup table. A programmer can store

widget references in it that he needs be disabled during the time an RPC

request in sent by not yet returned. This is useful for avoiding concurrency

Authors: Kou Man Tong, Fung Chak Fai 63

Page 64: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

issues where the user triggers some events that makes the program’s internal

states inconsistent before the RPC has returned. For example, we may have

an RPC call that would update the contents of a wtWindow widget when it is

returned successfully. If the user closes that wtWindow widget while the

RPC is being processed at the web server, then there would be nothing for it

to update when it is returned, and there would a JavaScript error. To avoid

this, the web developer can put the wtWindow widget into the RPC object’s

submitExclude lookup table, or the button widget that the user could use to

close the window into submitExclude. This disables the window widget or

the close window button during the time the RPC request is being submitted,

and so the application’s states would be consistent when the RPC has

returned.

3.2 The JSON Data Exchange FormatAlthough the name AJAX (Asynchronous JavaScript and XML) implies the

use of XML as the standard data exchange format, the XMLHttpRequest

object places no restriction on the data exchange format used in AJAX RPC

requests. Other data exchange formats can be used in AJAX remote

procedure calls, even binary data.

A popular alternative to XML that is used in AJAX RPC requests is JSON

(JavaScript Object Notation) [4]. The primary advantage of using JSON

instead of XML in web applications is that JSON can be directly converted

to and from JavaScript objects, while an XML string can only be directly

converted to and from a DOM node representing an XML document. This

makes JSON much easier to use than XML when client-side JavaScript

programming is concerned. As a result, JSON is used as the data exchange

format in place of XML in many popular web UI toolkits, such as in Dojo

Toolkit – “In addition, Dojo supports RPC using the JSON-RPC standard.”

[1] and in MochiKit – “… While this isn't directly relevant to MochiKit,

server-side code that produces JSON…”

(http://mochikit.com/doc/html/MochiKit/Async.html).

A related standard of using JSON as the data exchange format in web

applications is JSON-RPC (http://json-rpc.org/). WT Toolkit does not

support JSON-RPC at the moment, however.

Authors: Kou Man Tong, Fung Chak Fai 64

Page 65: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

3.3 Using the AJAX RPC System in Web ServerWhen an AJAX RPC is submitted from the client side via WT Toolkit, an

HTTP POST request is sent to the web server with two arguments. The first

POST argument is called ProcName, whose value is RPC call name entered

as the second argument when the wtRemoteProcedureCall object instance

was constructed. The purpose of the ProcName field is for the web server to

distinguish which function is requested by the RPC request. The second

POST argument is called ProcArgs, which is the JSON representation of the

data object.

To return data back to the client side, the web server simply needs to respond

with the JSON encoded data object.

To show how the server side programming works in a web application

written with WT Toolkit, we will use some server side code snippets from

one of our application demo – “francium’s Xanga Tracker” [27].

Figure 49 - The login window of francium's Xanga Tracker 0.1.8.

Authors: Kou Man Tong, Fung Chak Fai 65

Page 66: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

francium’s Xanga Tracker was written with Python and mod_python on the

server side. It uses a MySQL database as its permanent data store, the

SQLObject (http://www.sqlobject.org/ ) object relational manager for

database access, and the simplejson library

(http://cheeseshop.python.org/pypi/simplejson ) for encoding and decoding

JSON strings.

When an RPC request is received by the server part of francium’s Xanga

Tracker, the first thing it does it decoding the JSON string. This is done by a

very simple function called wtDecode() written in Python:

def wtDecode(reqObj):

if (not reqObj.has_key("ProcName")) or (not reqObj.has_key("ProcArgs")):

return None, {}

procName = reqObj["ProcName"]

procArgs = simplejson.loads(reqObj["ProcArgs"])

return procName, procArgs

Figure 50 - wtDecode() function in the server side of francium's Xanga Tracker.

In the code snippet above, the POST request fields are already de-serialized

into the reqObj argument – which is a mod_python FieldStorage object,

which works like a hash table (http://www.modpython.org/live/current/doc-

html/pyapi-util-fstor.html ). It took only one single line of code to decode the

incoming JSON string to a Python object, the “procArgs =

simplejson.loads(…” line.

def getSessionLog(req, **kw):

procName, procArgs = tracker_util.wtDecode(kw)

if procName == None:

return tracker_util.INVALID_RPC

login = tracker_util.getLogin(req)

if login == None:

return tracker_util.NOT_AUTHORIZED

user = db.User.getUser(login)

sortBy = procArgs["sortBy"]

sortOrder = procArgs["sortOrder"]

Authors: Kou Man Tong, Fung Chak Fai 66

Page 67: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

offset = procArgs["offset"]

sessionLog = user.getSessions(sortBy, sortOrder, offset)

return simplejson.dumps(sessionLog)

Figure 51 – Sending out the tracker log after the user clicks on the “Xanga Log” tab in Figure 17.

Figure 51 above is a mod_python publisher handler

(http://www.modpython.org/live/current/doc-html/hand-pub.html ) that is

used to send out the Xanga Tracker’s log to the web browser from the web

server. The procArgs variable seen here is the data object sent from the

browser in the RPC request. It can be seen in the last 5 lines of the program

that procArgs is used just like a regular Python dictionary in the server side.

The second last line of the program is a database query that returns an array

of log entries and the total number of log entries. The last line of the

program encodes the log entry array into a JSON string and sends that back

to the web client.

Figure 52 - Part of the returned string sent to the browser by getSessionLog().

Authors: Kou Man Tong, Fung Chak Fai 67

Page 68: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

4 Regular Widgets System4.1 Introduction

Figure 53 - Regular widget classes in WT Toolkit.

WT Toolkit includes a moderately large collection of regular GUI widgets.

The regular widgets cannot be used for form input and cannot be used for

drawing vector graphics.

API documentation of WT Tookit’s regular widgets system can be found at:

http://wt-toolkit.sourceforge.net/doc-0.3.2/overview-summary-wt_widget.js.html

4.2 The wtWidget ClassThe base class for most of the regular widget classes (except

wtNotebookPage) is the wtWidget class. It contains a set of operations that is

common to all regular widgets and form input widgets (which are explained

in Section 5).

Authors: Kou Man Tong, Fung Chak Fai 68

Page 69: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 54 - Operations of wtWidget class.

Some of the more interesting operations of the wtWidget class that are not

often found in other web UI toolkits and are quite troublesome to code

without a toolkit:

1. setAlpha() – Sets the alpha transparency of a widget.

2. setDraggable() – Makes the widget draggable.

Besides the operations, the wtWidget class also has a set of predefined

signals. Most of the wtWidget signals are user initiated events:

1. Click – the widget has been clicked.

2. MouseDown – the user has pressed a mouse button on this widget.

3. MouseOver – the mouse cursor is over this widget.

4. MouseOut – this mouse cursor has just pass away from this widget.

5. MouseUp – the user has released a mouse button on this widget.

6. Focus – this widget is being selected.

7. Blur – this widget is being deselected.

8. DoubleClick – the user has double clicked on the widget.

9. KeyDown – the user has lowered a key while this widget is selected.

10. KeyUp – this user has released a key while this widget is selected.

11. KeyPress – this lowered and released a key while this widget is selected.

Authors: Kou Man Tong, Fung Chak Fai 69

Page 70: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

12. Resize – the widget has been resized.

13. Move – the widget has been moved.

14. DragStart – the user has started dragging the widget around.

15. DragEnd – the user has finished dragging the widget around.

4.3 Example Widget ClasseswtWindow

Figure 55 - A few instances of wtWindow.

A wtWindow instance is a draggable container for other visible widgets. It

has a title, a scrollable container area and a soft shadow around the edges. It

can be disabled which turns it translucent and makes the contained widgets

unable to respond to user events.

wtImage

Authors: Kou Man Tong, Fung Chak Fai 70

Page 71: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 56 – The translucent backgrounds in the UML class title above are wtImage instances.

wtImage can be used to draw translucent .png images correclt under Internet Explorer 6 and 7.

A wtImage instance is very much like an <img/> tag in HTML. It provides

an extra functionality under Internet Explorer, however. In Internet Explorer

6, regular <img/> tags cannot render translucent .png files correctly; In

Internet Explorer 7, although <img/> tags can render translucent .png files,

setting alpha translucency on a translucent .png image would make .png

file’s translucency disappear. The wtImage class, on the other hand, can

render translucent .png files correctly under both Internet Explorer 6 and 7,

even if additional alpha translucency is applied to the image.

Authors: Kou Man Tong, Fung Chak Fai 71

Page 72: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

5 AJAX Forms System5.1 Introduction

One of the most obvious uses for AJAX RPC calls is to send user inputs to

the web server, and to receive response from the web server, without

refreshing the page. WT Toolkit has included an AJAX form system for this

task.

Figure 57 - Class diagram of WT Toolkit's AJAX form system.

API documentation of WT Toolkit’s AJAX form system can be found in the

following URL:

http://wt-toolkit.sourceforge.net/doc-0.3.2/overview-summary-wt_form.js.html

5.2 Using AJAX Forms in WT ToolkitThe wtForm Class

The wtForm class is a container for form input widgets. It contains a URL

and a RPC call name which are used to submit values to the server. It is very

much like a wtRemoteProcedureCall object where the data object is defined

by name and values of the form input widgets, instead of by the

programmer.

Authors: Kou Man Tong, Fung Chak Fai 72

Page 73: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

var form = new wtForm(“cgi/give_me_data.cgi”, “ProcessData”);

Figure 58 - Constructing an AJAX form.

The operations and events of the wtForm class are also very similar to the

wtRemoteProcedureCall class. Some of the similar operations include:

1. setSuccessHandler() – Sets the event handling function which would be

called back when form submission is successful.

2. setFailureHandler() – Sets the event handling function which would be

called back when form submission failed.

3. submit() – Submits the input form as an AJAX RPC request.

4. abort() – Aborts the current form submission.

The criteria of deciding whether a form submission is successful are also the

same as in wtRemoteProcedureCall. For example, if an AJAX form was

submitted and the web server did not respond within 5 seconds, the form

submission would be treated as a failure.

Some of the similar signals include:

1. SubmitSuccess – Same as the “Success” signal in

wtRemoteProcedureCall.

2. SubmitFailure – Same as the “Failure” signal in

wtRemoteProcedureCall.

Some events are unique to the wtForm class, however. For example:

1. ValueChanged – Emitted when one of the form widget’s value has

changed.

The “ValueChanged” signal in wtForm class is useful in verifying user

inputs, or notifying other objects in the web application UI of a change in

user input.

AJAX Form Widgets

With the exception of the classes wtSpreadSheet and wtVariableSpreadSheet,

most AJAX form widgets inherit from the wtFormWidget class. Every

wtFormWidget instance has a name and a value. Many wtFormWidget

descendents can also have a visible interface that lets the user change the

Authors: Kou Man Tong, Fung Chak Fai 73

Page 74: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

widget’s value.

Figure 59 - Some of the visible form widgets available in WT Toolkit

All form widgets have a setValue() and a getValue() operation for retrieving

and modifying its value. The name of a form widget is set at the constructor

and can not be changed once they have been constructed.

All form widget also have a common signal, ValueChanged. It can be used

to notify other objects in the web application UI of a specific form widget

being changed by the user, or by a setValue() call.

Submitting an AJAX Form

When an AJAX form is submitted, an AJAX RPC call is made to the web

server with the data object composed out of the (name, value) pairs of its

constituent form input widgets.

For example, if we have a wtForm instance who has two single-line

textboxes, named “input1” and “input2” respectively. The value of “input1”

at the time of AJAX form submission is “Hello World!”, and the value of

“input2” at the time of form submission is “Goodbye World!” The JSON

string sent to the web server as the ProcArg POST request field would be:

{“input1”:”Hello World!”, “input2”:“Goodbye World!”}

Handling Concurrency Issues

Authors: Kou Man Tong, Fung Chak Fai 74

Page 75: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Similar to the wtRemoteProcedureCall class, submitting an AJAX form may

incur concurrency issues. For example, the user may change the form’s

values while the AJAX form is being submitted. The wtForm class

implemented in WT Toolkit is able to disable any constituent form widgets

while the form is being submitted and the RPC call has not yet returned.

Moreover, if the programmer wishes to disable other visible widgets, he can

add that visible widget into the submitExclude lookup table of the wtForm

instance, which works the same as in wtRemoteProcedureCall.

5.3 Example Input Form

Figure 60 - Login window of francium's Xanga Tracker.

The login window in francium’s Xanga Tracker, one of WT Toolkit’s

application demonstrations, contains an AJAX form. The AJAX form here

has two user inputs, the login name, and the password. The “Login” button

submits the form to web server.

Authors: Kou Man Tong, Fung Chak Fai 75

Page 76: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 61 - Input form is grayed out and disabled when AJAX form is being submitted.

When the form is being submitted, i.e. the “Login” button has been pressed

but the server has not replied yet. The whole form would be grayed out and

is disabled to the user. In the figure above, the “New User…” button, which

is not part of the AJAX form, is gray out and disabled as well. This is

because the web developer has added the “New User…” button to the

submitExclude lookup table of login form. Another change that has occurred

during form submission is that the submit button has changed to an “Abort”

button.

Figure 62 - The user is notified of a failed login if he enters a wrong username, password pair.

If the user has entered a wrong username, password pair to the login form,

he will be notified of a login failure when the client side UI has received a

response from the web server.

Authors: Kou Man Tong, Fung Chak Fai 76

Page 77: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 63 - Another window with Xanga log entries are displayed after a successful login.

If the user has entered the correct username, password pair in the login form,

then the login form window would disappear, and a new window appears

which displays his Xanga page visitor log.

Authors: Kou Man Tong, Fung Chak Fai 77

Page 78: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

6 Vector Graphical Widgets System6.1 Introduction

The vector graphical widgets system in WT Toolkit allows drawing vector

graphics in Internet Explorer 6+ and Gecko-based browsers (e.g. Firefox)

without requiring any third party plug-in. Vector graphics are drawn by

adding VML [19] nodes under the document tree in Internet Explorer, and

by adding inline SVG [30] nodes to the document tree in web browsers

using the Gecko engine.

Apart from being able to draw simple shapes like ellipses, polygons and

lines, the vector graphics system in WT Toolkit is also able to construct

more sophisticated and tangible widgets. For example, we can construct 3D

objects and many different kinds of charts, such as 3D bar charts, 3D pie

charts, broken line charts, curve line charts, scatter charts, radar charts, etc.

Figure 64 - Vector graphics drawn with WT Toolkit.

API documentation for the vector graphical widgets system can be found in

the following URL:

http://wt-toolkit.sourceforge.net/doc-0.3.2/overview-summary-wt_vector.js.html

6.2 Base Components of the Vector Graphics

Authors: Kou Man Tong, Fung Chak Fai 78

Page 79: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

SystemThe wtVectorWidget Class

All vector graphical widgets in WT Toolkit are subclasses of the

wtVectorWidget Class. Unlike its HTML counterpart, wtWidget, the

wtVectorWidget class does not offer a lot of features. It also does not emit

any signals. The purpose of wtVectorWidget is purely for drawing graphics,

not for interacting with the user.

Figure 65 - Although there are a lot of operations under the wtVectorWidget class, most of them

serve only to change the appearance of the graphical widget.

The wtVectorGroup Class

To make vector graphical widget emit user events, graphical widgets must

be group together in a wtVectorGroup instance. The wtVectorGroup class

offers some operations that are similar to those found in wtWidget. For

example:

1. setDraggable() – makes a group of vector graphical widgets draggable.

2. setAbsolutePosition() – adds an (x,y) coordinate offset to the graphical

widget’s original positions.

The wtColor Class

The fill and stroke color of all simple vector graphics widgets can be

modified by the setFillColor() and setStrokeColor() operations. These two

Authors: Kou Man Tong, Fung Chak Fai 79

Page 80: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

operations accept many kinds of color arguments. For example, they can

accept CSS color code words, like “red”, “blue”, “gray”, “darkblue”, etc.

They can also accept a wtColor instance as the argument with which the user

can define colors as RGB, HSV and RGBA values. For example:

vectorWidget.setFillColor(new wtColor("rgba", {"red":255, "green":255, "blue":255, "alpha":127}));

Figure 66 - Setting a graphical widget's fill color to be white with 50% opacity.

The alpha channel in wtColor allows graphical widgets to be colored with

translucency. For three circles shown in Figure 64, for example, are colored

with a translucent alpha channel.

Figure 67 - Three overlapping circles colored with a translucent alpha channel.

The wtColor class can also generate new colors based on the current

wtColor instance. It does so by adding or subtracting RGB or HSV values to

the current color. This is useful in drawing 3D objects. For example, there is

a green 3D box in Figure 65 which was constructed from the wtBar class.

Figure 68 - Green 3D box in Figure 65.

window.myBar1 = new wtBar(canvas,30,50,30,45,"green");

Figure 69 – The green 3D box in JavaScript.

Authors: Kou Man Tong, Fung Chak Fai 80

Page 81: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

The green 3D box has three visible sides, with the top side and the right side

being somewhat darker than the front side. In constructing the green 3D box,

the programmer only has to tell WT Toolkit that the box’s color is “green”,

he does not have to tell WT Toolkit how to color the darker sides. This is

possible because the wtBar class has automatically generated the darker

shades with wtColor by subtracting the value of V channel in the HSV

representation of “green”.

6.3 Charting EngineMany different kinds of charts can be drawn with WT Toolkit’s charting

engine. These include:

3D bar charts;

Figure 70 - A 3D bar chart.

Stacked bar charts;

Authors: Kou Man Tong, Fung Chak Fai 81

Page 82: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 71 - A 3D stacked bar chart.

Bar charts with data items separated on the category axis;

Figure 72 - Another 3D bar chart.

Authors: Kou Man Tong, Fung Chak Fai 82

Page 83: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Line charts, with curves or broken lines;

Figure 73 - A line chart with curves and broken lines.

Stacked line charts;

Figure 74 - A stacked line chart.

Authors: Kou Man Tong, Fung Chak Fai 83

Page 84: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Scatter charts;

Figure 75 - A scatter chart drawn with WT Toolkit.

3D pie charts, with the “pies” separated or combined;

Figure 76 - A few pie charts drawn with WT Toolkit.

Authors: Kou Man Tong, Fung Chak Fai 84

Page 85: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Radar charts;

Figure 77 - Two radar charts drawn with WT Toolkit.

6.4 G=(V,E) Graph EngineThe G=(V,E) graph engine in WT Toolkit allows user interactive G=(V,E) to

be constructed in web applications. A demonstration video has been posted

to YouTube showing the interactive features of a G=(V,E) graph drawn with

WT Toolkit, in the following URL:

http://www.youtube.com/watch?v=QmSpj7MOo6k

Authors: Kou Man Tong, Fung Chak Fai 85

Page 86: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Figure 78 - Interactive G=(V,E) video demonstration in YouTube.

6.5 3D ObjectsSimple 3D objects can be constructed in WT Toolkit. A 3D object animation

demonstration video has been posted to YouTube:

http://www.youtube.com/watch?v=KCKsGOff1vI

Figure 79 - Video showing rotating cubes drawn with WT Toolkit.

6.6 Live DemonstrationsA few live demonstrations showing the features of WT Toolkit’s vector

graphical engine has been posted to our SourceForge project website.

1. Vector widgets demonstration:

Authors: Kou Man Tong, Fung Chak Fai 86

Page 87: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

http://wt-toolkit.sourceforge.net/demo/vector_widget.html

Many of the screen captures shown in Section 6 are captured from this

demonstration page.

Figure 80 - Vector widgets demonstration running in Firefox 2.0.

Authors: Kou Man Tong, Fung Chak Fai 87

Page 88: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

2. Interactive charting demonstration:

http://wt-toolkit.sourceforge.net/demo/charting_demo.html

Figure 81 - A screenshot of our interactive charting demonstration.

3. Interactive UML editor:

http://wt-toolkit.sourceforge.net/demo/test_wtumlclass.html

All the UML class and instance diagrams in this report are drawn with

our UML editor built upon WT Toolkit. So, while you are reading this

report, you are already looking at a partial demonstration of the UML

editor.

Authors: Kou Man Tong, Fung Chak Fai 88

Page 89: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

7 ConclusionsIn this final year project report, we have described the object model and event

handling system of WT Toolkit. We have compared our object model and event

handling system to two other popular toolkits: Dojo Toolkit and Yahoo! UI Toolkit.

We have shown that our object model and event handling system are immune to cross

page memory leaks in Internet Explorer 6, and are less vulnerable to lapsed listeners

when compared to Dojo Toolkit or Yahoo! UI Toolkit.

Then, we have described our AJAX RPC system. Our RPC system uses JSON as the

data exchange format in sending and receiving data objects to and from the web

server. Our AJAX RPC system does not support the JSON-RPC standard yet, which

other similar toolkits like Dojo Toolkits and MochiKit have already supported. Our

AJAX RPC system has built-in mechanisms for avoiding concurrency issues with

user initiated events that were emitted when the RPC is being processed.

We have built a fairly comprehensive UI widget system that includes a moderately

wide range of visible widgets. User interactive features can be implemented by

connecting event listeners to the user signals of UI widgets. Notable features of our

toolkit include alpha transparency, transparent PNG image support under Internet

Explorer, and translucent windows.

An AJAX form system has been implemented in WT Toolkit. It works very similarly

compared to the AJAX RPC system. Our form widget system is more flexible when

compared to dojo.io.bind() method in Dojo Toolkit because we allow building new

and custom form widgets by object oriented methods like aggregation and inheritance.

We have implemented a vector graphics system in WT Toolkit. Our vector graphics

system allows the use of colors with alpha channel for coloring widgets. Graphics

widgets can be made user interactive as widget groups, which is useful when we need

make an aggregated graphical widget interactive instead of having every single basic

shape in the graphical widget being interactive.

Finally, some sophisticated graphical widgets and tangible widgets with real

applications have been implemented in WT Toolkit’s vector graphical engine. Many

different kinds of charts, 2D and 3D, can be constructed with WT Toolkit. Interactive

G=(V,E) graphs can be constructed with WT Toolkit. A UML editor application has

been implemented as a live demonstration of WT Toolkit’s G=(V,E) graph

Authors: Kou Man Tong, Fung Chak Fai 89

Page 90: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

capabilities. All class diagrams and instance diagrams in this report are drawn with

our UML Editor.

Authors: Kou Man Tong, Fung Chak Fai 90

Page 91: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

8 References[1] Roland Barcia. Build enterprise soa ajax clients with the dojo toolkit and

json-rpc. http://www-128.ibm.com/developerworks/websphere/library/techarticles/

0606 barcia/0606 barcia.html?ca=dgr-lnxw07Dojo-Ajax-SOA, June 2006.

[2] Mihai Bazon. Ie: where’s my memory?

http://www.bazon.net/mishoo/articles.epl?art id=824, August 2004.

[3] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford

Stein. Introduction to Algorithms, chapter 21. MIT Press, 2001.

[4] Douglas Crockford. Json: The fat-free alternative to xml.

http://2006.xmlconference.org/proceedings/176/presentation.html, 2006.

[5] Flickr. Welcome to flickr - photo sharing. http://www.flikr.com, 2007.

[6] Dojo Foundation. The dojo toolkit. http://www.dojotoolkit.org, 2007.

[7] Dojy Foundation. Degradable ajax forms with dojo.

http://dojotoolkit.org/node/227, January 2006.

[8] Free Software Foundation. Gnu lesser general public license (lgpl).

http://www.opensource.org/osi3.0/licenses/lgpl-license.php.

[9] The Apache Software Foundation. Apache/python integration.

http://www.modpython.org/, February 2007.

[10] Ethan Henry and Ed Lycklama. How do you plug java memory leaks? Dr.

Dobbs Journal, February 2000.

[11] HKUST. Vela startup. http://vela.ust.hk, 2006.

[12] HKUST. Hkust - webct homepage. http://webct.ust.hk/, April 2007.

[13] Google

Inc. Welcome to google docs and spreadsheets. http://docs.google.com,

2007.

[14] Carol King. Peoplesoft ships web-based erp solu-

tion. http://www.internetnews.com/infra/article.php/452911, September

2000.

[15] Martin LaMonica. Microsoft gets

hip to ajax. http://news.com.com/Microsoft+gets+hip+to+AJAX/2100-10073-

5765197.html, June 2005.

[16] PePLink Ltd. Introduction to peplink central management system.

http://www.peplink.com/document/PePLink_PCMS_whitepaper_introduction.pdf,

2006.

[17] PePLink Ltd. Peplink announces integrated remote management solution.

http://www.pepwave.com/index.php?view=news&news_category id=2&news_id=9,

April 2006.

Authors: Kou Man Tong, Fung Chak Fai 91

Page 92: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

[18] PePLink Ltd. Peplink supplies wi-fi cpe to st. cloud, fl.

http://www.pepwave.com/index.php?view=news&news_category id=2&news_id=7,

March 2006.

[19] Brian Mathews, Daniel Lee, Brian Dister, John Bowler, Howard Coop-

erstein, Ajay Jindal, Tuan Nguyen, Peter Wu, and Troy Sandal. Vector

markup language (vml). http://www.w3.org/TR/NOTE-VML.html, May

1998.

[20] Tropos Networks. Tropos networks

introduces first metro-compliant specification for wi-fi access equipment.

http://www.tropos.com/news/pressreleases/2006_05_03.php, May 2006.

[21] Monica Pawlan. Reference objects and garbage collection. Reference Ob-

jects and Garbage Collection, August 1998.

[22] Justin Rogers. Understanding and solving internet explorer leak pat-

terns. http://msdn.microsoft.com/library/default.asp?url=/library/en-

us/ietechcol/dnwebgen/ie_leak_patterns.asp, June 2005.

[23] Alex Russell. Now whered i put that reference.

http://alex.dojotoolkit.org/?p=526, December 2005.

[24] sakaiproject.org. Lmes 2.1a. http://lmes2.ust.hk, 2007.

[25] Bruce A. Tate. Bitter Java, chapter 6. Manning Publications Co., 2002.

[26] Team and Concepts Ltd. Online spreadsheets - editgrid.

http://www.editgrid.com, 2007.

[27] Kou Man Tong. francium’s xanga tracker. http://hkpcug.homeftp.net,

2007.

[28] (Unknown). Drip ie leak detector.

http://www.outofhanwell.com/ieleak/index.php?title=Main_Page.

[29] (Unknown). Jsdoc - javascript documentation tool.

http://jsdoc.sourceforge.net/.

[30] SVG Wiki. Inline svg. http://wiki.svg.org/index.php?title=Inline_SVG,

March 2007.

[31] Wikipedia. Ajax (programming).

http://en.wikipedia.org/w/index.php?title=Ajax_%28programming

%29&oldid=76779850, June 2006.

[32] Wikipedia. Rich internet application.

http://en.wikipedia.org/w/index.php?

title=Rich_Internet_application&oldid=75889738, June 2006.

[33] Wikipedia. Observer pattern.

http://en.wikipedia.org/w/index.php?

title=Observer_pattern&direction=prev&oldid=105135192, February 2007.

Authors: Kou Man Tong, Fung Chak Fai 92

Page 93: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

9 Appendix A: Source Code for Finding Programming Patterns Prone to Memory Leaks in Internet Explorer 69.1 Leak Experiments with Simple Circular

References<html>

<head>

<title>Circular reference within a DOM object leaks memory in Internet Explorer</title>

<script language="javascript">

function init()

{

// first, we construct a DOM node

var node = document.createElement("div");

node.innerHTML = "I'm leaked away!";

// then, we make a circular reference like this:

// DOM node -> DOM node

// for control experiment, assign null instead.

node.circularReference = node;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 82 - A DOM node referring to itself via an attribute.

Authors: Kou Man Tong, Fung Chak Fai 93

Page 94: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<html>

<head>

<title>Circular reference between a DOM object and another DOM object leaks memory

in Internet Explorer</title>

<script language="javascript">

// this is actually worse than the other cases - both nodes are leaked because both are referenced in a

// circle

function init()

{

// construct the first DOM node and attach it to the document tree

var node = document.createElement("div");

node.innerHTML = "I'm leaked away!";

node.id = "node";

document.body.appendChild(node);

// construct the second DOM node and attach it to the document tree

var intermediateNode = document.createElement("div");

intermediateNode.id = "intermediateNode";

intermediateNode.innerHTML = "I'm also leaked away!";

document.body.appendChild(intermediateNode);

// now, make a circular reference path like this:

// DOM node A -> DOM node B -> DOM node A

// for control experiment, comment out any one of the following two lines

node.circularReferencePart1 = intermediateNode;

intermediateNode.circularReferencePart2 = node;

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 83 - Two DOM nodes referring to each other.

Authors: Kou Man Tong, Fung Chak Fai 94

Page 95: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<html>

<head>

<title>Circular reference between a JS object and a DOM object leaks memory in Internet

Explorer</title>

<script language="javascript">

function init()

{

// first, we construct a DOM node

var node = document.createElement("div");

node.innerHTML = "I'm leaked away!";

// then, we make a Javascript object

var jsobj = new Object();

// then, we make a circular reference like this:

// DOM node -> JS object -> DOM node

// for control experiment, comment out any one of the two lines below

node.circularReferencePart1 = jsobj;

jsobj.circularReferencePart2 = node;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 84 - A DOM node referring to itself via a Javascript object.

Authors: Kou Man Tong, Fung Chak Fai 95

Page 96: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<html>

<head>

<title>Circular reference between two Javascript objects does not leak memory in Internet

Explorer</title>

<script language="javascript">

function init()

{

// first, we construct a DOM node and attach it the the document tree

var node = document.createElement("div");

node.innerHTML = "I'm NOT leaked away!";

node.id = "node";

document.body.appendChild(node);

// then, we construct a Javascript object and add the DOM node to it.

var jsobj = new Object();

jsobj.domNode = node;

// then, we construct another Javascript object

var jsobj2 = new Object();

// finally, we create a circular reference like this:

// JS object A -> JS object B -> JS object A

jsobj.circularReference1 = jsobj2;

jsobj2.circularReference2 = jsobj;

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 85 - Two Javascript objects referring to each other, with a DOM node attached to one of

the objects as an indicator such that any leak can be detected via Drip.

Authors: Kou Man Tong, Fung Chak Fai 96

Page 97: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

9.2 Leak Experiments with Closures<html>

<head>

<title>Circular reference between DOM node and a closure via implicit binding of

variables leaks memory in Internet Explorer</title>

<script language="javascript">

function makeAnotherClosureForControlExperiment()

{

window.g = function(){alert(this);}

}

function init()

{

// first, we construct a DOM node

var node = document.createElement("div");

node.innerHTML = "I'm leaked away!";

// then, we create an empty closure

// it doesn't even need to refer to "node" or "this"

// for the circular reference to happen

var f = function(){}

// then, we create a circular reference like this:

// DOM node -> closure -> DOM node

// if you want to perform a control experiment, comment out the line below

node.f = f;

// for a control experiment, we make another closure

// that cannot possibly refer back to "node" implicitly

// but rather, it can refer back to "node" via the "this" reference

// interestingly, this one does NOT leak

makeAnotherClosureForControlExperiment();

node.g = window.g;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

Authors: Kou Man Tong, Fung Chak Fai 97

Page 98: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

document.body.appendChild(node);

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 86 - Closure declared in the same scope as a DOM node, and assigning that closure as

the DOM node's attribute.

<html>

<head>

<title>This example shows that containing a DOM node within a Javascript object cannot

prevent the memory leak</title>

<script language="javascript">

function makeAnotherClosureForControlExperiment()

{

window.g = function(){alert(this);}

}

function init()

{

// first, we construct a DOM node, contained in a JS object

var jso = {"node" : document.createElement("div")};

jso.node.innerHTML = "I'm leaked away!";

// then, we create an empty closure

// it doesn't even need to refer to "node" or "this"

// for the circular reference to happen

// if you want to perform a control experiment, comment out the line below

var f = function(){}

// then, we create a circular reference like this:

// DOM node -> closure -> JS Object -> DOM node

jso.node.f = f;

Authors: Kou Man Tong, Fung Chak Fai 98

Page 99: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

// for a control experiment, we make another closure

// that cannot possibly refer back to "node" implicitly

// but rather, it can refer back to "node" via the "this" reference

// interestingly, this one does NOT leak

makeAnotherClosureForControlExperiment();

jso.node.g = window.g;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(jso.node);

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 87 – Same as the last experiment, except that the DOM node is put inside a Javascript

object such that identifiers inside the closure cannot be bound to the DOM object directly.

<html>

<head>

<!--

This test case came from http://www.bazon.net/mishoo/articles.epl?art_id=824

where the author used one more closure to fix the closure memory leak bug

-->

<title>This examples shows that creating the DOM node with another closure prevents

the memory leak</title>

<script language="javascript">

function init()

{

// first, create an empty closure

var f = function(){}

var h = function()

{

// now, we construct a DOM node

var node = document.createElement("div");

Authors: Kou Man Tong, Fung Chak Fai 99

Page 100: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

node.innerHTML = "I'm NOT leaked away!";

// notice that no circular reference has been created

// because the closure f cannot refer back to our DOM node via "node"

// but it can still do so via "this"

node.f = f;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

}

h();

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 88 - Trying to avoid circular references via closures with even more closures. This test

case is modified from one of the suggested solutions mentioned in Bazon's article.

9.3 Leak Experiment with Function Objects<html>

<head>

<title>Circular reference between DOM node and a non-closure function object does not

leaks memory in Internet Explorer</title>

<script language="javascript">

function init()

{

// first, we construct a DOM node

var node = document.createElement("div");

node.innerHTML = "I'm NOT leaked away!";

// then, we create an empty function object

// a function object created this way cannot refer to variables defined in the outer scope

var f = new Function("");

Authors: Kou Man Tong, Fung Chak Fai 100

Page 101: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

// then, we create a circular reference like this:

// DOM node -> function object -> DOM node

node.f = f;

// finally, we attach the DOM node to the document tree

document.body.appendChild(node);

}

</script>

</head>

<body onload="init()">

</body>

</html>

Figure 89 - Making a function object by calling the Function class constructor within the same

scope of a DOM node, and assigning the function object as a DOM node attribute.

Authors: Kou Man Tong, Fung Chak Fai 101

Page 102: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

10 Appendix B: Source Code for Finding JavaScript Operations Affected by Memory Leaks in Internet Explorer 6

<html>

<head>

<title>Circular reference within a DOM object leaks memory in Internet Explorer</title>

<script language="javascript">

function leakOne()

{

// first, we construct a DOM node

var node = document.createElement("div");

// then, we make a circular reference like this:

// DOM node -> DOM node

node.circularReference = node;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

placeNode(node);

}

function placeNode(node)

{

// place the node randomly on the page

var x = parseInt(Math.random() * 800) + "px";

var y = parseInt(50 + Math.random() * 750) + "px";

node.style.position = "absolute";

node.style.top = y;

node.style.left = x;

node.style.width = "1px";

node.style.height = "1px";

node.style.fontSize = "1px";

node.style.backgroundColor = "black";

}

function getTime()

Authors: Kou Man Tong, Fung Chak Fai 102

Page 103: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

{

return (new Date()).getTime();

}

function leak2000()

{

var begin = getTime();

for(var i=0;i<2000;i++)

leakOne();

var end = getTime();

alert("Creating 2000 nodes took " + (end - begin) + "ms");

}

function init(){}

</script>

</head>

<body onload="init()">

<a href="javascript: leak2000();">Create 2000 DIV nodes</a>

</body>

</html>

Figure 90 – Each time the link “Create 2000 DIV nodes” is clicked, 2000 self-referencing DOM

nodes are created.

<html>

<head>

<title>Circular reference between a DOM object and another DOM object leaks memory

in Internet Explorer</title>

<script language="javascript">

// this is actually worse than the other cases - both nodes are leaked because both are referenced in a

circle

function leakOne()

{

// construct the first DOM node and attach it to the document tree

var node = document.createElement("div");

document.body.appendChild(node);

Authors: Kou Man Tong, Fung Chak Fai 103

Page 104: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

// construct the second DOM node and attach it to the document tree

var intermediateNode = document.createElement("div");

document.body.appendChild(intermediateNode);

// now, make a circular reference path like this:

// DOM node A -> DOM node B -> DOM node A

node.circularReferencePart1 = intermediateNode;

intermediateNode.circularReferencePart2 = node;

placeNode(node);

placeNode(intermediateNode);

}

function placeNode(node)

{

// place the node randomly on the page

var x = parseInt(Math.random() * 800) + "px";

var y = parseInt(50 + Math.random() * 750) + "px";

node.style.position = "absolute";

node.style.top = y;

node.style.left = x;

node.style.width = "1px";

node.style.height = "1px";

node.style.fontSize = "1px";

node.style.backgroundColor = "black";

}

function getTime()

{

return (new Date()).getTime();

}

function leak2000()

{

var begin = getTime();

for(var i=0;i<1000;i++)

leakOne();

Authors: Kou Man Tong, Fung Chak Fai 104

Page 105: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

var end = getTime();

alert("Creating 2000 nodes took " + (end - begin) + "ms");

}

</script>

</head>

<body onload="init()">

<a href="javascript: leak2000();">Create 2000 DIV nodes</a>

</body>

</html>

Figure 91 – Each time the link “Create 2000 DIV nodes” is clicked, 1000 pairs of circular

referencing DIV nodes are created.

<html>

<head>

<title>Circular reference between a JS object and a DOM object leaks memory in Internet

Explorer</title>

<script language="javascript">

function leakOne()

{

// first, we construct a DOM node

var node = document.createElement("div");

// then, we make a Javascript object

var jsobj = new Object();

// then, we make a circular reference like this:

// DOM node -> JS object -> DOM node

node.circularReferencePart1 = jsobj;

jsobj.circularReferencePart2 = node;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

placeNode(node);

}

function placeNode(node)

Authors: Kou Man Tong, Fung Chak Fai 105

Page 106: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

{

// place the node randomly on the page

var x = parseInt(Math.random() * 800) + "px";

var y = parseInt(50 + Math.random() * 750) + "px";

node.style.position = "absolute";

node.style.top = y;

node.style.left = x;

node.style.width = "1px";

node.style.height = "1px";

node.style.fontSize = "1px";

node.style.backgroundColor = "black";

}

function getTime()

{

return (new Date()).getTime();

}

function leak2000()

{

var begin = getTime();

for(var i=0;i<2000;i++)

leakOne();

var end = getTime();

alert("Creating 2000 nodes took " + (end - begin) + "ms");

}

</script>

</head>

<body onload="">

<a href="javascript: leak2000();">Create 2000 DIV nodes</a>

</body>

</html>

Figure 92 – Each time the link “Create 2000 DIV nodes” is clicked, 2000 DIV nodes each with a

reference to itself via a Javascript object is created.

<html>

Authors: Kou Man Tong, Fung Chak Fai 106

Page 107: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

<head>

<title>Circular reference between DOM node and a closure via implicit binding of

variables leaks memory in Internet Explorer</title>

<script language="javascript">

function leakOne()

{

// first, we construct a DOM node

var node = document.createElement("div");

// then, we create an empty closure

// it doesn't even need to refer to "node" or "this"

// for the circular reference to happen

var f = function(){}

// then, we create a circular reference like this:

// DOM node -> closure -> DOM node

node.f = f;

// finally, we attach the DOM node to the document tree

// this step is not required for the leak to happen

document.body.appendChild(node);

placeNode(node);

}

function placeNode(node)

{

// place the node randomly on the page

var x = parseInt(Math.random() * 800) + "px";

var y = parseInt(50 + Math.random() * 750) + "px";

node.style.position = "absolute";

node.style.top = y;

node.style.left = x;

node.style.width = "1px";

node.style.height = "1px";

node.style.fontSize = "1px";

node.style.backgroundColor = "black";

}

Authors: Kou Man Tong, Fung Chak Fai 107

Page 108: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

function getTime()

{

return (new Date()).getTime();

}

function leak2000()

{

var begin = getTime();

for(var i=0;i<2000;i++)

leakOne();

var end = getTime();

alert("Creating 2000 nodes took " + (end - begin) + "ms");

}

</script>

</head>

<body onload="">

<a href="javascript: leak2000();">Create 2000 DIV nodes</a>

</body>

</html>

Figure 93 – Each time the “Create 2000 DIV nodes” link is clicked, 2000 DIV nodes each with a

reference to itself via a closure is created.

Authors: Kou Man Tong, Fung Chak Fai 108

Page 109: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

11 Appendix C: Source Code for Showing JavaScript Object Creation Latency Deteriorating with Number of Reachable JavaScript Objects under Internet Explorer

<html>

<head>

<script>

var arr = [];

function createObjects()

{

var o = null;

for(var i=0;i<10000;i++)

o = new Object;

}

function createDummyObjects(n)

{

for(var i=0;i<n;i++)

arr.push(new Object);

}

function benchmark()

{

var startTime = (new Date()).getTime();

createObjects();

var endTime = (new Date()).getTime();

var node = document.createElement("div");

var time = endTime - startTime;

node.appendChild(document.createTextNode("Creating 10000 objects in addition to " + arr.length +

" objects: " + time + "ms"));

document.body.appendChild(node);

return time;

}

Authors: Kou Man Tong, Fung Chak Fai 109

Page 110: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

function makeDummies()

{

createDummyObjects(20000);

}

function runAPass()

{

makeDummies();

benchmark();

if (arr.length < 400000)

setTimeout(runAPass, 500);

}

function clicked()

{

benchmark();

setTimeout(runAPass, 500);

}

</script>

</head>

<body>

<a href="javascript: clicked()">Run Benchmark</a>

</body>

</html>

Figure 94 - Demonstration code for showing JavaScript object creation latency deteriorating with

number of reachable JavaScript Objects, under Internet Explorer 6 and 7.

<html>

<head>

<script>

var nodeCount = 0;

function createObjects()

{

var o = null;

for(var i=0;i<10000;i++)

o = new Object;

Authors: Kou Man Tong, Fung Chak Fai 110

Page 111: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

}

function createOneDummy()

{

var div = document.createElement("div");

div.innerHTML = "Hello World!";

div.style.position = "absolute";

div.style.left = "-1000px";

div.style.top = "-1000px";

document.body.appendChild(div);

nodeCount++;

}

function createDummyObjects(n)

{

for(var i=0;i<n;i++)

createOneDummy();

}

function benchmark()

{

var startTime = (new Date()).getTime();

createObjects();

var endTime = (new Date()).getTime();

var node = document.createElement("div");

var time = endTime - startTime;

node.appendChild(document.createTextNode("Creating 10000 objects in addition to " + nodeCount

+ " DOM nodes: " + time + "ms"));

document.body.appendChild(node);

return time;

}

function makeDummies()

{

createDummyObjects(2000);

}

Authors: Kou Man Tong, Fung Chak Fai 111

Page 112: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

function runAPass()

{

makeDummies();

benchmark();

if (nodeCount < 40000)

setTimeout(runAPass, 500);

}

function clicked()

{

benchmark();

setTimeout(runAPass, 500);

}

</script>

</head>

<body>

<a href="javascript: clicked()">Run Benchmark</a>

</body>

</html>

Figure 95 - Control experiment. Here, although the memory usage of iexplorer.exe is also

increasing progressively, JavaScript object creation latency does not deteriorate because the

number of reachable JavaScript objects is not increasing.

Authors: Kou Man Tong, Fung Chak Fai 112

Page 113: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

12 Appendix D: Conversations in Dojo Interest Mailing List Regarding the Lapsed Listeners in Dojo Toolkit

Hi,

Since my server is in Hong Kong where the international links are down at

the moment, you may have difficulty reaching my server. Therefore I'm

attaching my testing code in a .zip file attachment.

Thanks.

Best Regards,

Martin Kou

From: "Kou Man Tong, Martin" <eg_kmt at stu.ust.hk>

To: <dojo-interest at dojotoolkit.org>

Cc: <cs_fcf at stu.ust.hk>

Sent: Monday, January 01, 2007 1:31 PM

Subject: [Dojo-interest] Memory leakage in dynamically created widgets?

> Hi,

>

> I've sent this question three times to the mailing list yesterday and for

> the first two times the mailing server thought I was spamming it. The

> mailing server didn't respond to my third mail, but by now I suspect it

> was silently marked as spam and dropped. So I'm sending this question

> again from a different email address.

>

> Here's my previous mail, if it is repeated, sorry about that:

>

> I'm new to Dojo Toolkit - I've just started learning it last week. I

> started learning it by writing some simple, proof-of-concept dynamic pages

> (where widgets can be created and destoryed without being refreshed - I

> haven't touched on the ajax stuff yet). I think I've done something wrong,

> and I've tried things like dojo.event.browser.clean() that popped up in

> this mailing list and Alex's December 2005 blog entries for similar

Authors: Kou Man Tong, Fung Chak Fai 113

Page 114: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

> problems, but to no avail.

>

> First page I constructed with Dojo:

> http://hkpcug.homeftp.net/~francium/dojo-0.4.1-ajax/dojo_leak_dom.html

>

> Second page I constructed with Dojo:

> http://hkpcug.homeftp.net/~francium/dojo-0.4.1-ajax/dojo_leak_widget.html

>

> In both examples, clicking "Creating xxx widgets" and then "Destroy All"

> repeatedly in IE6 or IE7 would lead to the vmsizes of both browsers (as

> observed from Window's Task Manager) increase rapidly. How can I correct

> this problem? And could anyone kindly point to the reason why is it

> happening?

>

> Best regards,

> Martin Kou

>

> _______________________________________________

> Dojo FAQ: http://dojo.jot.com/FAQ

> Dojo Book: http://manual.dojotoolkit.org/DojoDotBook

> Dojo-interest at dojotoolkit.org

> http://dojotoolkit.org/mailman/listinfo/dojo-interest

Figure 96 – Original problem statement.

URL: http://dojotoolkit.org/pipermail/dojo-interest/2007-January/023056.html

Thanks for the information. It does indeed like what you say. I tested on

two browsers(IE 7.0 and Opear9.01).

Well the destroy is only cleaning up the browser but not the memory. In fact

it adds to the memeory size after cleaning the browser!.

In my Task manager I cannot find the Memory Usage History tab which would

have given more information. References on the web gives a hint as to why

this may be happening. The leakage problem is often associated with the dom

elements (the widget) being created inside a script.

The following IE specific article may give you a hint:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/

Authors: Kou Man Tong, Fung Chak Fai 114

Page 115: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

ie_leak_patterns.asp

Jayaram

Figure 97 – Third party confirmation of problem.

URL: http://dojotoolkit.org/pipermail/dojo-interest/2007-January/023132.html

In all fairness to dojo the increase is not exponential for Martin's example code.

At first 19240 K

First click 25108 K

Second Click 29960 K

Third click 35544 K

Fourth click 40540 K

Fifth click 46104 k

At Destroy 583428K

But the effect is substantial slowdown.

Figure 98 – Third party confirmation of problem.

URL: http://dojotoolkit.org/pipermail/dojo-interest/2007-January/023180.html

Hi Martin,

On Wednesday 03 January 2007 10:22 am, Martin Kou wrote:

> I've read that MSDN article quite a long while ago (I think January

> 2006? I so wished Microsoft would crash and burn upon reading that

> article for the first time), it mostly deals with memory leaks

> related to circular references in which IE's garbage collector cannot

> clean up. As far as I know, I believe such memory leaks can always be

> detected with Drip if the circular references still exist after the

> page is unloaded.

Drip tries to "force" the issue in a wrapped IE ActiveX control, but

I've observed leakage that Drip can't find (in the XHR object, for

instance).

Authors: Kou Man Tong, Fung Chak Fai 115

Page 116: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

> I think the leak I'm seeing here is different. Testing the pages with

> Drip turns up with negative results. Also, as I understand, Dojo's

> event system does not store the event handler given directly under

> the subject - it stores the handler elsewhere and puts a generic

> handler function to, say, the onclick attribute. So I believe it is

> not possible for the "traditional" DOM object -> closure -> DOM

> object kind of leak to happen under Dojo, as long as I use its event

> system instead of assigning closures to DOM nodes directly.

>

> In the createOne() function of the dojo_leak_dom.html test case,

> there exists a closure -> DOM object link between "node" and

> "clickHandler", because clickHandler can refer back to node

> implicitly. Just take my word that such a reference exists even if

> the clickHandler is an empty closure, but I can provide a proof to

> you if you care.

No, I believe you. There's enough else wrong w/ the JScript heuristics

around memory that it wouldn't surprise me that the closure dehydration

code is over-broad. That, or it's a hedge against runtime deref w/

something like obj["propName"], but even that doesn't make much sense.

> Now, assume Dojo's event system does not create circular references

> with dojo.event.connect() - this assumption is reasonable because

> Dojo's event system was claimed to be designed specifically to avoid

> this problem (http://alex.dojotoolkit.org/?p=526). It can, however,

> still leak memory before a page is unloaded by doing one of the two

> things:

It should be noted that the reference is *created*, we just take pains

to clean out the dom -> js references before final page GC happens.

> 1. Keeping a reference to the DOM node, even after it is detached

> from the document tree

Shouldn't be a problem. It's the reference in the other direction that

the collector can't find (and therefore can't free). That's the

reference set we try hard to break.

Authors: Kou Man Tong, Fung Chak Fai 116

Page 117: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

> 2. Keeping a reference to the clickHandler, even after its associated

> DOM node is detached from the document tree

See last note.

> These items "leak" memory because as long as I keep a reference that

> can be traced back to the DOM node, the DOM node would not be freed,

> even by a correctly implemented garbage collector (So Firefox leaks

> memory in my dojo_leak_dom.html test cases as well... it leaks slower

> than IE, but the leak is still observable).

>

> Item 2 can leak memory because the clickHandler keeps an implicit

> reference back to the DOM node. But right now I'm guessing point 1 is

> true now because, following Matthew's advice, I've tried to set node

> = null at the end of the createOne() function, thus breaking the

> clickHandler -> node link

See above note. The DOM object is a COM-bound C++ representation of the

DOM item, and it's the reference held *by that C++ structure* that the

JScript interpreter's GC chokes on. References in JS to the object

should be OK since the refcount can be decremented correctly when the

environment is cleared out.

Obviously, this is predicated on pseudo-sane behavior from IE, an

assumption that has failed me in the past, but my experimental evidence

tends to suggest that removing the dom -> js linkage is enough to

prevent leakage.

You might add a call to JScript-specific window.CollectGarbage() method

to ensure that your test page is really showing you what you think it's

showing you.

Regards

[snipped]

--

Alex Russell

Authors: Kou Man Tong, Fung Chak Fai 117

Page 118: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

alex at sitepen.com A99F 8785 F491 D5FD 04D7 ACD9 4158 FFDF 2894 6876

alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723

Figure 99 – First response from Alex Russell, Dojo project founder.

http://dojotoolkit.org/pipermail/dojo-interest/2007-January/023143.html

On Wednesday 03 January 2007 1:12 am, Martin Kou wrote:

> Here's a video of what happend, notice the VM size was increasing

> rapidly as I clicked create and destroy. This is incorrect behavior

> since the VM size indicates the virtual memory address space

> allocated to the browser.

>

> http://hkpcug.homeftp.net/~francium/leak_demo.swf.html

>

> (2.1MB video warning)

Just to be very clear, unless I'm seeing the video wrong, what you're

describing is increasing memory usage *in a single page*. Leakage, as

is usually defined WRT MSIE, is defined by un-recovered memory across

page loads, not an increase in memory footprint inside the same page

environment.

We may be able to do something about the later, but we've spend our time

dealing with the former to date, as it has truly debilitating

consequences for long-term usage.

Regards

[snipped]

--

Alex Russell

alex at sitepen.com A99F 8785 F491 D5FD 04D7 ACD9 4158 FFDF 2894 6876

alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723

Figure 100 – Second response from Alex Russell, showing that Dojo is still focused on solving

memory leakage problems caused by circular referencing in Internet Explorer 6.

URL: http://dojotoolkit.org/pipermail/dojo-interest/2007-January/023144.html

Authors: Kou Man Tong, Fung Chak Fai 118

Page 119: FYP_Final_Report_2.doc.doc

Final Report – Powerful AJAX Tools for Lightweight Portable Web User Interfaces

Authors: Kou Man Tong, Fung Chak Fai 119