Dorado 5 : 附录:AJAX开发的性能影响 使用AJAX提高Web应用的带宽性能

原文:
http://webperformanceinc.com/library/reports/AjaxBandwidth/index.html

Performance Impacts of AJAX Development:

Using AJAX to Improve the Bandwidth Performance of Web Applications

Christopher L Merrillchris AT webperformance.com ©2006 Web Performance, Inc January 15, 2006v1.0

Introduction

Being a performance company, we are always interested in the impact of new development techniques on the performance of web applications. We have numerous customers who have performance problems due primarily to the size of their web pages. Put another way - the pages are simply too big to achieve the desired performance goals with the available bandwidth. In some cases, the page consists primarily of content that is common between many pages. For instance, a header, footer and navigation menu that change infrequently, if at all, during the use of the application. This suggested that if the application was only updating the part of the page that needed to change, a considerable amount of bandwidth could be saved.

The Goal

In order to test the theory, we decided to see if we could cut the bandwidth use of an application by at least 50%. We selected a rather simple internal data-analysis application. The application consists of a typical page layout with a central section containing the changing content. The header, footer and navigation menu do not change during the application operation. We modified the application so that it can be accessed in either traditional (page-refresh) mode or AJAX mode. We then used our measurement tool (Web Performance Analyzer) to record and analyze the bandwidth utilization of each application.

Results

The first result of this effort surprised us a little. With all the talk of AJAX frameworks, we expected to have a difficult time choosing an appropriate AJAX framework to use in our application. After trying a few simple experiments with a few popular frameworks, and learning just enough Javascript to be dangerous, we settled on a simple collection of javascript functions to accomplish our goals. We were able to pull a few code snippets from various Javascript/AJAX tutorials around the 'net and with less than 100 lines of javascript (and some refactoring of our web-app) we converted the application to use AJAX. No frameworks needed.The second result confirmed our expectation - we were able to cut the bandwidth usage of the application by 61%. The chart below shows some bandwidth statistics for the two versions of the application:

scenario/mode

first-page size

typical page size

total bandwidth

Page-refresh

44k

10k

210k

AJAX

47k

2.5k

81k

TOTAL BANDWIDTH SAVINGS > 61%

Where did the savings come from?

Below are screenshots from our measurement tool (Web Performance Analyzer) showing the page/url transaction sizes for the original application (page-refresh mode) and the AJAX version. As you can see from the list of URLs and sizes below, the AJAX-mode application actually made the first page of the application larger. In our test, it was approximately 3k larger. This is not surprising, since this page contains the additional javascript required to drive the AJAX mode. If an AJAX framework had been chosen, we would expect this increase to be considerably larger.Most notable is that the typical page size decreased from ~10k to ~2.5k - a reduction of 75%. Figure 1 - Bandwidth requirements in page-refresh mode figure 2 - bandwidth requirements in AJAX mode

How We Did It

To achieve the bandwidth savings, we made a handful of modifications to our application.

Application-mode switch

First we added an application-mode switch. This used a context parameter in the web-application descriptor that the application could query to determine if it was in AJAX or page-refresh mode. Note that this step would be unnecessary in most applications.

HTML Form widget changes

Next we modified the HTML form widgets to change the form-submission mechanism. As an example, here is the starting tag for a SELECT element (drop-down list) before and after the modifications:
<SELECT name="type" onChange="window.document.theform.submit()"><SELECT name="type" onChange="submitForm()">
The SELECT element will now call a javascript function (see below) instead of using the browser to submit the form.

HTML SPAN element around the form

In order to mark the section of HTML that is to be replaced dynamically by the content returned from the server, it is placed inside a SPAN element named with an identifier we can use in our javascript functions:
<span id="content_area">

Javascript functions

Next we wrote or scavenged several javascript functions to perform the AJAX-mode form submission and page update.The first is the submitForm() method referenced in the SELECT elements (described above). This method is called to replace the browsers form-submission logic. The submission is accomplished in two steps:

  1. Build a string containing the content to submit.
  2. Submit the content to the specified URL with a callback method to be invoked when the operation is completed.

submitForm()

function submitForm() { var content = convertFormDataToPostContent(window.document.theform); doPost('/office/UsageAnalyzer', content, 'processResult'); }

Look at the third parameter in the doPost() method call: 'processResult'. This is the name of our callback method. When the asynchronous method is completed, this method will be called with the result. The job of the processResult() method (below) is to update the document with the result of the post. Note that the 'content_area' parameter to the getElementById() method is the same as the id of the SPAN element we added to our HTML. processResult()

function processResult(result) { document.getElementById('content_area').innerHTML = result; }

The work of submitting the content in a POST transaction to the server is relatively simple. It creates a browser-specific request object, submits the content and creates a function used to perform the callback with the content returned by the server. This code was scavenged from the Internet and can be readily found in many AJAX articles or frameworks. doPost()

function doPost(url, content, callback_name) { var async_request = false; // Mozilla/Safari if (window.XMLHttpRequest) { async_request = new XMLHttpRequest(); async_request.overrideMimeType('text/xml'); } // IE else if (window.ActiveXObject) { async_request = new ActiveXObject("Microsoft.XMLHTTP"); } async_request.open('POST', url, true); async_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); async_request.onreadystatechange = function() { if (async_request.readyState == 4) { response_content = async_request.responseText; eval(callback_name + '(response_content);'); } } async_request.send(content); }

The form-field conversion method traverses the list of fields in the form and encodes them into the proper format for submission as a form-urlencoded post. Again, this code was scavenged from sources on the Internet. convertFormDataToPostContent()

function convertFormDataToPostContent(form_name) { var content_to_submit = ''; var form_element; var last_element_name = ''; for (i = 0; i < form_name.elements.length; i++) { form_element = form_name.elements[i]; switch (form_element.type) { // Text fields, hidden form elements case 'text': case 'hidden': case 'password': case 'textarea': case 'select-one': content_to_submit += form_element.name + '=' + escape(form_element.value) + '&' break; // Radio buttons case 'radio': if (form_element.checked) { content_to_submit += form_element.name + '=' + escape(form_element.value) + '&' } break; // Checkboxes case 'checkbox': if (form_element.checked) { // Continuing multiple, same-name checkboxes if (form_element.name == last_element_name) { // Strip of end ampersand if there is one if (content_to_submit.lastIndexOf('&') == content_to_submit.length - 1) { content_to_submit = content_to_submit.substr( 0, content_to_submit.length - 1); } // Append value as comma-delimited string content_to_submit += ',' + escape(form_element.value); } else { content_to_submit += form_element.name + '=' + escape(form_element.value); } content_to_submit += '&'; last_element_name = form_element.name; } break; } } // Remove trailing separator content_to_submit = content_to_submit.substr(0, content_to_submit.length - 1); return content_to_submit; }

Conclusion

In applications that have a significant part of each page containing content that is identical in multiple page requests, using AJAX-style methods to update only the relevant parts of a web page can bring significant bandwidth savings. Using less than 100 lines of javascript, we were able to quickly convert an existing web application to use AJAX page-update methods to drastically reduce (>60%) the bandwidth requirements of our sample application.It is important to note that the application converted in our test was ridiculously simple. Achieving the same bandwidth reduction on a sophisticated application will likely not be as easy, if it is possible at all. However, when applied to extremely large-scale applications or applications with very tight bandwidth considerations, savings of 10% could bring a hefty cost savings.

Future Directions

It would be interesting to test a more realisitic application that has been converted from a previous version to use AJAX in the method described here. If you know of such an application, please contact us!The impact on server CPU resources would also be an interesting study. However, given that none of the "fluff" on our pages requires any database queries or other processing work, our reference application may not be the best choice for this test.If you have a preference for what you would like to see in future versions, please make your voice heard in our forum.

Feedback & Comments

An on-line forum is provided for discussing the details, results and merits of this report.

Version History

v1.0 - 1st public release (15 jan 06)
webperformanceinc.com

about the company

Founded in 1999, Web Performance Inc is based in Research Triangle Park, North Carolina. It was founded by web technology experts who saw a growing demand for easy to use web testing software that was appropriate to use on projects of all sizes, especially during the early development stages. Web Performance Inc has been profitable since early 2000, and is not dependent on venture capital.
The catalyst for the founders came after consulting on a web-based product for a huge multinational company. Although the product was weeks away from launch, no performance testing had been done, and preliminary informal feedback from the pre-release was that the product was very slow. A survey of the existing products turned up no software that could be purchased quick enough to meet the roll-out deadline. The complexity of the software meant that the testing personnel would have to attend classes to learn how to use it, and the high cost meant that the purchase would have to be approved at the highest levels of management, all of which would take time, and would significantly delay the product launch.
The solution was to create a new type of web testing software that allows for complete and thorough testing of the performance of a web site without having to spend weeks or months developing scripts. Unfortunately for this client, the tests showed that the bottleneck was in the database API-- it was single threaded, meaning only one user could access the web site at a time! In the end the entire database layer had to be rewritten, taking months and costing hundreds of thousands of dollars. This situation could have been avoided if even simple performance tests had been done at the earliest stages of the product.
Web Performance Trainer&trade (A Personal Trainer For Your Website) was formed out of this experience, designed to help web site development teams test performance from the minute the project is started, to after it has been deployed in the field. It was designed to require no lengthy training period, and to be available immediately with a simple download.
We are guided by the following principles:
Software should be a pleasure to use We believe the tools one uses every day should be a pleasure to use, and this definitely includes software. This goes beyond the usual standard of "quality", which usually means the software doesn't crash too often, and embraces the idea of transparency and depth. Transparency means once you get used to the software, it should be so intuitive the user doesn't have to think about using it. Depth means that software should be easy to use, even if you don't know much about what it does, and as you learn more about the subject, you discover more features of the program.
Developers Should Interact With CustomersMost companies place a wall between the people who create software and the people who use the software. At WPI software developers talk directly with customers, both in the pre and post sales process, which not only benefits the customer, but greatly helps the product as well. For example, with most products when customers have the same question over and over again it gets placed in a FAQ, and anyone asking the question gets a canned response from a technical support person with no real power to make improvements.
Information should be sharedMany companies selling software operate by hiding information, giving access only to their customers. What type of information is hidden? Tutorials, feature lists, bug lists, price lists, all are handed out only to those who can pass the screening test of the sales office. We believe the web itself is proof of the benefits of open access to information, and have built this web site accordingly.

AJAX开发的性能影响:

使用AJAX提高Web应用的带宽性能

Christopher L Merrillchris AT webperformance.com ©2006 Web Performance, Inc 2006年1月15日v1.0

介绍

作为关注性能的公司,我们一直对"新的开发技术对Web应用性能影响"倍感兴趣。我们有无数的困扰性能问题的客户,这些问题主要是由于他们的Web页面的大小引起的。页面太大,以至于难以在现有可用的宽带上达到设计的性能指标。在有些情况下,页面主要由一些在许多页面间都是相同的内容构成。比如,标题,页脚与导航菜单都极少变动,甚至在整个应用的使用期间。这表示,如果应用只更新需要更新的部分,则可以节约相当大的带宽。

目标

为了检测该理论,我们决定去看看我们是否能够省下某个应用至少50%的带宽。我们选择了一个非常简单的互联网数据分析应用。这个应用由一个典型的页面设计构成,页面中间部分是包括变化的内容。标题、页脚与导航菜单在应用使用期间都不变化。我们改进了应用使其能够以传统方式(页面刷新)模式与AJAX模式任何一种方式访问。我们使用的我们的测试工具(Web Performance Analyzer)来记录与分析每个应用的带宽利用率。

结果

最初的结果让我们有点吃惊。AJAX的许多框架下,我们预期很难选择一种合适的AJAX框架来用在我们的应用中。在尝试了某几个流行框架的几个简单试验后,同时充分领略了Javascript的危险性后,我们固化了一组简单的javascript功能来完成目标。我们能够从网上不同的Javascript/AJAX指南中截取一小段代码,少于100行的javascript(一些重新分解了我们的web应用)我们修改了应用来使用AJAX。没有使用框架。
第二个结果证实了我们的预期——我们能够减少61%的应用带宽使用。下表显示了两个版本应用的一些带宽统计数字。

场景/模式

首页大少

典型页面大小

宽带总计

Page-refresh

44k

10k

210k

AJAX

47k

2.5k

81k

总计节约带宽 > 61%

这些节约来自何处?

以下是我们测试工具的屏幕截图(Web Performance Analyzer) ,表明最初应用(页面刷新模式)与AJAX版本的页面/url 交易大小。正如您从下面的URLs与大小所能看到的,AJAX模式的应用实际上使应用的第一个页面更大。在我们的测试中,它大约大了3k。这并不奇怪,因为这个页面包含了驱动AJAX模式的所需的传统javascript。如果一个选择了AJAX框架,我们可以预期这个增大将变得相当大。
最值得关注的是典型页面大小从10k减少为2.5k——75%的减少率。 图 1 - 页界刷新模式下所需的带宽 图 2 - AJAX模式下所需的带宽

我们是如何做的

为了取得节约带宽的目标,我们对我们的应用做了一些改动。

应用模式切换

首先我们增加了一个应用模式切换。在web应用描述符中用到了一个context参数,这样应用就可以询问来决定是否是AJAX模式或页面刷新模式。注意,在一步在大多数应用中是不必要的。

改变HTML Form widget

下一步我们改变了HTML form widgets来改变form提交机制。作为一个示例,这里是改变前后的SELECT元素的开始的tag。
<SELECT name="type" onChange="window.document.theform.submit()"><SELECT name="type" onChange="submitForm()">
这个SELECT 元素将调用javascript 函数 (如下) 而不是利用浏览器来提交这个form。

form 周围的HTML SPAN 元素

为了标记HTML部分使之能被返回自服务器的内容所动态地替换,它在内部放置了一个SPAN元素由一个标识符命名,这个标识符我们能用在我们的javascript函数中:
<span id="content_area">

Javascript函数

接下来,我们写了或者清除了数个javascript函数执行AJAX模式form提交与更新。第一个是SELECT 元素 (上文已描述)引用的 submitForm() 方式。调用这个方法来替代浏览器form提交逻辑。提交由两步完成:

  1. 构建一个包含提交内容的字符串。
  2. 提交内容至一个指定的URL ,当操作完成时,附带一个被调用的callback 方法。

submitForm()

function submitForm() { var content = convertFormDataToPostContent(window.document.theform); doPost('/office/UsageAnalyzer', content, 'processResult'); }

请看第三个参数在 doPost() 方法中调用: 'processResult'. 这是我们的callback 方法。当异步方式完成时,这个方法将带着结果被调用。 processResult() 方法 (如下)的工作是以发布的结果更新文件。注意:getElementById() 方法中的'content_area' 参数是与我们所增加至我们HTML的SPAN元素的id相同。
processResult()

function processResult(result) { document.getElementById('content_area').innerHTML = result; }

在发布交易到服务器中提交内容是相应地简单的。它创建了一个browser-specific request object,提交内容并创建一个函数用以执行服务器返回内容的callback。这些代码提取自互联网,在许多AJAX文章与框架中可以容易地获得。
doPost()

function doPost(url, content, callback_name) { var async_request = false; // Mozilla/Safari if (window.XMLHttpRequest) { async_request = new XMLHttpRequest(); async_request.overrideMimeType('text/xml'); } // IE else if (window.ActiveXObject) { async_request = new ActiveXObject("Microsoft.XMLHTTP"); } async_request.open('POST', url, true); async_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); async_request.onreadystatechange = function() { if (async_request.readyState == 4) { response_content = async_request.responseText; eval(callback_name + '(response_content);'); } } async_request.send(content); }

form-field 转化方法穿越form的字段列表,把它们编码为适当的格式来作为form-urlencoded发布提交。又一次,这些代码来自于互联网上的资源。 convertFormDataToPostContent()

function convertFormDataToPostContent(form_name) { var content_to_submit = ''; var form_element; var last_element_name = ''; for (i = 0; i < form_name.elements.length; i++) { form_element = form_name.elements[i]; switch (form_element.type) { // Text fields, hidden form elements case 'text': case 'hidden': case 'password': case 'textarea': case 'select-one': content_to_submit += form_element.name + '=' + escape(form_element.value) + '&' break; // Radio buttons case 'radio': if (form_element.checked) { content_to_submit += form_element.name + '=' + escape(form_element.value) + '&' } break; // Checkboxes case 'checkbox': if (form_element.checked) { // Continuing multiple, same-name checkboxes if (form_element.name == last_element_name) { // Strip of end ampersand if there is one if (content_to_submit.lastIndexOf('&') == content_to_submit.length - 1) { content_to_submit = content_to_submit.substr( 0, content_to_submit.length - 1); } // Append value as comma-delimited string content_to_submit += ',' + escape(form_element.value); } else { content_to_submit += form_element.name + '=' + escape(form_element.value); } content_to_submit += '&'; last_element_name = form_element.name; } break; } } // Remove trailing separator content_to_submit = content_to_submit.substr(0, content_to_submit.length - 1); return content_to_submit; }

结论

在应用中,一个在每一个页面中包含内容的有效部分与多页面请求相同,使用AJAX风格的方法来更新一个web页面中的相关部分能够带来相当可观的带宽节约。在我们的示例中,使用少于100行的javascript,我们能够快速地将一个现存的web应用转化为AJAX页面更新方法,来显著地减少(>60%)的带宽需求。
需要特别注意之处,在我们的测试中应用转化是相当的简单。在一个复杂的应用中达成同样的带宽减少将可能不很容易,假如这是完全可行的。然而,当应用于一个极端大型的应用或者需要考虑非常紧张的带宽的应用,节约10%将带来极大的成本节约。

未来性指南

这里所描述的是一个有趣的方法,来测试一个更加现实的从先前的版本修改为使用AJAX应用。如果你知道有这样一个应用,请联系我们! 研究服务器CPU资源的影响非常有趣。然而,假设我们的页面中没有任何"无价值的东西"或者其它处理工作,我们的参考应用可能不是这个测试的最好选择。
如果你就未来版本所想看到的有所偏爱,请使你的声音为论坛所知。

反馈与评注

提供一个在线论坛来讨论这份报表的细节,结论与价格。

版本历史

v1.0 ——第一次公开发表 (2006年1月15日)