web应用程序和web网站_改善Web应用程序的性能

web应用程序和web网站

总览

富Internet应用程序(RIA)在Web 2.0域中非常流行。 为了提供新颖新颖的用户体验,许多网站都使用JavaScript或Flash将其复杂的内容从后端服务器移至客户端。 如果数据大小相当小,这将提供方便,时尚和流畅的用户界面(UI)。 如果必须将大量内容从服务器传输到客户端并在浏览器中呈现,则性能将明显下降。 挑战在于找到瓶颈并找到解决方案。

与浏览器而不是Java应用程序相比,调整性能问题更加困难。 开发人员在每种浏览器中调试JavaScript的方式较少。 使用Mozilla Firefox,您可以使用Firebug调试JavaScript,但是仍然不能调整许多性能问题,例如浏览器渲染消耗的时间。 为了解决这些问题,开发浏览器插件以监视时间响应以及识别其他相应的解决方案(如部分渲染或延迟加载)至关重要。

学习诊断Web应用程序的性能问题,找到客户端内容中的瓶颈,并调整性能。

JavaScript和HTML DOM

JavaScript是Internet上最流行的脚本语言。 数以百万计的网页设计师使用JavaScript来改善他们的设计,验证输入表单,检查浏览器并创建cookie。 HTML文档对象模型(DOM)定义了访问和操作HTML文档的标准方法。 它将HTML文档表示为节点树,其中包含元素,属性和文本内容。

通过使用HTML DOM,JavaScript可以访问HTML文档中的所有节点,然后对其进行操作。 几乎所有主流浏览器都支持JavaScript和HTML DOM,并且大多数网站都使用它。 使用它们时的性能会严重影响RIA的整体性能。

JavaScript性能和功能

使用JavaScript,当您需要一个函数时,请使用一个函数。 尽管在某些情况下可以使用字符串而不是函数,但是我们建议您尽可能使用函数。 函数在JavaScript中使用之前已进行了预编译。

例如,查看清单1所示的eval方法。

清单1.使用字符串作为参数的eval方法
function square(input) {
  var output;
  eval('output=(input * input)');
  return output;
}

eval方法对输入进行平方并返回输出值,但是性能不会很好。 该示例使用字符串output=(input*input)作为eval方法的参数,该参数无法利用JavaScript预编译。

清单2显示了一种更好的方法。

清单2.使用函数作为参数的Eval方法
function square(input) {
  var output;
  eval(new function() { output=(input * input)});
  return output;
}

使用函数而不是字符串作为参数可确保JavaScript编译器优化了新方法中的代码。

功能范围

JavaScript函数作用域链中的每个作用域均包含多个变量。 了解作用域链非常重要,这样您就可以利用这些好处。 清单3显示了一个函数范围的示例。

清单3.函数范围
function test() {
  var localVar = “test”;
  test1(this. localVar);
var pageName = document.getElementById(“pageName”);
}

图1显示了作用域链结构。

图1.范围链结构
为了充分利用范围链,了解范围链的结构非常重要

使用局部变量比使用全局变量快得多,因为变量在链中的距离越远,解析度就越慢。

如果代码中包含withtry-catch语句,则作用域链更为复杂。 图2显示了try-catch语句的作用域链。

图2.try-catch作用域链结构
链结构中的try-catch语句使其更加复杂

字符串函数

JavaScript中最不希望使用的功能之一是字符串连接。 它通常使用+号来完成这项工作。 清单4显示了一个示例。

清单4.字符串连接
var txt = “hello” + “ ” + “world”;

该语句创建几个中间字符串以包含串联结果。 幕后字符串的不断创建和破坏导致非常糟糕的字符串连接性能。 早期的浏览器没有针对此类操作的优化。 我们建议您为实现创建一个StringBuffer类,如清单5所示。

清单5. StringBuffer对象
function StringBuffer() {
this.buffer = [];
}

StringBuffer.prototype.append = function append(val) {
 this.buffer.push(val);
 return this;
}

StringBuffer.prototype.toString = function toString () {
 return this.buffer.join(“”);
}

所有属性和方法都在字符串对象上定义(而不是值)。 当您引用字符串值的属性或方法时,ECMAScript引擎必须在运行该方法之前隐式创建一个与您的字符串具有相同值的新字符串对象。 该对象仅用于该特定请求,并且在您下次尝试使用字符串值的方法时将重新创建。

在这种情况下,对将多次调用其方法的那些字符串使用新的语句。

清单6显示了一个新的字符串对象的示例。

清单6.创建新的字符串对象的示例
var str = new String(“hello”);

StringObject.indexOf比StringObject.match快。 搜索简单字符串匹配时,请尽可能使用indexOf而不是正则表达式匹配。

除非绝对必要,否则避免与非常长的字符串(10KB或更大)匹配。 如果确定匹配只会发生在字符串的特定部分,请选择一个子字符串并与之比较,而不是与整个字符串进行比较。

DOM性能

本节概述了可以调整以提高DOM性能的一些事情。

重涂

如果以前看不见的东西变为可见,则DOM将重新绘制,反之亦然。 重绘也称为重绘。 该行为不会更改文档布局。 不会更改元素的大小,形状或位置但会改变其外观的任何内容都会触发重新绘制。

例如,添加轮廓或更改元素的背景颜色将提示重新绘制。 就性能而言,这种重涂是昂贵的。 它要求引擎搜索所有元素以确定现在可见的内容以及必须显示的内容。

回流焊

与重涂相比,重排是更重要的更改。 回流:

  • DOM树被操纵。
  • 更改样式会影响布局。
  • 元素的className属性已更改。
  • 浏览器窗口大小已更改。

引擎将对相关元素进行重排,以标识现在必须在何处显示各个零件。 子元素也将被重排以反映其父元素的新布局。 出现在DOM中的元素之后的元素也将被重排以计算其新布局,因为它们可能已被初始重排所移动。 祖先元素也将重排以说明其子元素大小的变化。 最后,所有内容都会重新粉刷。

每次向文档中添加元素时,浏览器都必须对页面进行重排,以计算出所有内容的放置和呈现方式。 您添加的内容越多,其重排就越多。 如果您可以减少添加的单独元素的数量,则浏览器的工作量将减少,因此执行速度将更快。

CSS性能

将层叠样式表(CSS)放在顶部。 如果样式表位于底部,则将最后加载它们。 在此之前,页面将完全空白几秒钟,而浏览器则等待样式表加载,然后再在页面上呈现其他任何内容(包括静态文本)。

使用Internet Explorer,@ @import行为与使用底部的<link>相同。 我们建议您不要使用它。

速记属性

使用速记属性在单个声明中一次设置多个属性,而不是对每个单独的属性使用单独的声明。 使用速记属性,可以减小文件大小并减少维护。

例如,您可以设置背景,边框,边框颜色,边框样式,边框边(边框顶部,边框右边,边框底部和边框左边),边框宽度,字体,列表样式,边距,轮廓和填充属性。

CSS选择器

CSS选择器通过从右移到左进行匹配。 如清单7所示,浏览器必须遍历页面中的每个锚元素,并确定其父级的ID是否为aElement

清单7.选择器从右到左匹配
#aElement > a{
    font-size: 18px;
}

如果从代码中删除> ,如清单8所示,性能会下降。 浏览器必须检查整个文档中的每个锚点。 而且,浏览器不仅要检查每个锚点的父级,还必须爬上文档树并查找ID为aElement的祖先。 如果要评估的锚点不是 aElement的后代,则浏览器必须遍历祖先树,直到到达文档根目录为止。

清单8.如果没有>,性能会恶化
#aElement a{
    font-size: 18px;
}

最佳实践

本节概述了一些最佳实践,这些最佳实践将帮助您改进和改善Web应用程序的性能。

减少HTTP请求的数量

每个HTTP请求都有开销,包括搜索DNS,创建连接和等待响应,因此减少请求数可以减少不必要的开销。 要减少请求数量:

  • 合并文件。 将始终同时需要的脚本组合到一个文件中不会减少整体大小,但会减少请求数量。 您也可以通过类似的方式组合CSS文件和图像。 您可以自动实现文件合并:
    • 在构建步骤中。 使用<concat>标记,通过运行Ant合并文件。
    • 在运行时步骤。 启用mod_concat模块。 如果httpServer是Apache,则使用pack:Tag作为JSP taglib来组合JavaScript和样式表文件。 (pack:Tag是一个JSP-Taglib,它最小化,压缩和合并诸如JavaScript和CSS之类的资源,并将它们缓存在内存或生成的文件中。)
  • 使用CSS Sprites。 将背景图像合并为单个图像,并使用CSS background-image和background-position属性显示所需的图像段。 您还可以使用嵌入式图像来减少请求数量。

后加载组件

仅渲染绝对需要的组件; 其他人可以等待。 最好避免一次渲染太多元素。

在某些情况下,您可以使用后加载。 由于可以后加载浏览器可见区域之外的组件,因此可以在这些组件首次进入可见区域时立即启动初始渲染。

可以在onload事件之后对JavaScript的某些部分进行后加载,例如在初始呈现后在JavaScript中拖动元素。

预装组件

通过预加载组件,您可以利用浏览器的空闲时间并请求将来需要的组件(例如图像,样式和脚本)。 当用户访问下一页时,如果大多数组件已经加载到缓存中,则页面加载速度将大大提高。

有两种类型的预加载:

  • 无条件:onload触发后,您将获取一些额外的组件。
  • 有条件的:根据用户的操作,您可以对用户下一步的去向进行有根据的猜测,并相应地进行预加载。

将脚本放在底部

脚本可能会出现问题,因为它们会阻止并行下载。 在下载脚本时,浏览器不会启动其他任何下载,即使下载的主机名称不同。 将脚本(如样式表)放在底部,以便在其他加载完成后下载脚本。

您还可以使用仅Internet Explorer支持的延迟脚本。 DEFER属性指示脚本不包含document.write() 。 这是浏览器可以继续渲染的线索。

使用无Cookie的域组件

当浏览器发出静态图像请求并与请求一起发送cookie时,服务器将不使用这些cookie中的任何一个。 由于cookie仅创建不必要的网络流量,因此请确保使用无cookie请求来请求静态组件。 然后使用一个子域并在其中托管所有静态组件。

将JavaScript和CSS设为外部

在现实世界中使用外部文件通常会产生更快的页面,因为JavaScript和CSS文件是由浏览器缓存的。 每次请求HTML文档时,都会下载HTML文档中内联JavaScript和CSS。 这减少了所需的HTTP请求数量,但增加了HTML文档的大小。 另一方面,如果JavaScript和CSS位于浏览器缓存的外部文件中,则HTML文档的大小会减小而不会增加请求的数量。

RIA小部件性能

主流RIA Ajax框架(例如ExtJS,YUI,Dojo等)都提供了精美的小部件库,以增强用户体验。 与其他框架相比,由于以下原因,Dojo在企业开发领域更胜一筹:

  • 面向对象编程(OOP)编码
  • 跨平台
  • Dojo离线API对本地数据存储的支持
  • DataGrid,2D和3D图形(图表组件提供了一种在浏览器中呈现报表的简便方法)

Dojo已在许多网站中广泛使用。 我们将以Dojo为例来分析RIA小部件的性能。 您可以使用许多用于Dojo小部件调整的工具,例如Page Speed,Rock Star Optimizer和Jiffy。 我们强烈建议您使用YSlow和Firebug。

慢速

YSlow通过根据高性能网页的一组规则检查网页上的所有组件(包括使用JavaScript创建的组件)来分析网页性能。 YSlow是与Firebug Web开发工具集成的Firefox附加组件。 它提供了改善页面性能的建议,总结了页面的组成部分,显示了有关页面的统计信息,并提供了性能分析工具。

图3显示了“ YSlow成绩”选项卡上的信息示例。

图3. YSlow Grade选项卡
YSlow Grade面板是Firefox附加组件的一部分

YSlow的网页分析基于22条可测试的规则,下面以重要性和有效性的大致顺序列出了这些规则。 研究表明,遵循以下规则可以将网页响应时间提高25%到50%:

  • 最小化HTTP请求。
  • 使用内容传送网络。
  • 添加一个Expires或Cache-Control标头。
  • Gzip组件。
  • 将样式表放在顶部。
  • 将脚本放在底部。
  • 避免使用CSS表达式。
  • 将JavaScript和CSS设置为外部。
  • 减少DNS查找。
  • 缩小JavaScript和CSS。
  • 避免重定向。
  • 删除重复的脚本。
  • 配置ETag。
  • 使Ajax可缓存。
  • 使用GET处理Ajax请求。
  • 减少DOM元素的数量。
  • 消除404。
  • 减少Cookie的大小。
  • 对组件使用无cookie域。
  • 避免使用过滤器。
  • 不要缩放HTML中的图像。
  • 使favicon.ico较小且可缓存。

YSlow Statistics选项卡(如图4所示)使您可以比较您的页面大小(带有空缓存的访问者)和以前访问过页面的访问者。

图4. YSlow Statistics选项卡
YSlow Statistics面板比较页面大小

“组件”选项卡显示每个组件以及有关性能的相关信息。 例如,您可以查看是否压缩了组件,或者ETag是什么(如果有)。 组件大小和有效期也显示在“组件”选项卡中, 如图5所示。

图5. YSlow Components选项卡
YSlow Component面板显示很多相关信息,包括大小和到期日期

萤火虫

Firebug与Mozilla Firefox集成在一起,可在您浏览时将大量开发工具置于您的指尖。 您可以在任何网页中实时编辑,调试和监视CSS,HTML和JavaScript。

您可以使用Firebug Net面板(如图6所示)来监视由网页启动的HTTP通信。 它将所有收集和计算的信息呈现给用户。 每个条目代表页面进行的一次请求/响应往返。

图6. Firebug网络
Firebug Net面板从页面监控流量

Firebug控制台面板(如图7所示)提供了两种监视代码性能的方法。

图7. Firebug控制台面板
Firebug控制台面板可帮助监视您的代码性能
个人资料
对于特定功能,请使用Profiler。 JavaScript Profiler是有用的Firebug功能,可测量每个JavaScript代码的执行时间。 使用JavaScript Profiler可以提高代码的性能或调查为什么某个特定功能花了这么长时间。 它类似于console.time(),但是JavaScript Profiler可以为您提供有关代码正在发生的事情的更多详细信息。
console.time()
对于特定的代码段,请使用console.time()。 控制台显示您在命令行中输入的命令结果。 您可以使用console.time(timeName)函数来衡量特定代码或函数所花费的时间。 如果您想提高JavaScript代码的性能,则此功能非常有用。 清单9显示了一个示例。
清单9. console.time()示例
var timeName = 'measuringTime';  
console.time(timeName); //start of the timer   
for(var i=0;i<1000;i++){  
//do something  
console.timeEnd(timeName);  //end of the timer

measuringTime:xxms将被打印在控制台中。

Dojo小部件性能

本节探讨分析和改善Dojo小部件性能的方法。

装车费用

正如“ 提高基于Dojo的Web应用程序的性能 ”(E. Lazutkin,2007年2月)中指出的那样,大多数Dojo用户的第一印象就是它很大。例如,dojo-release-1.5.0-src.zip是19M,甚至压缩的软件包dojo-release-1.5.0.zip仍然是4.5M。最小版本中的大多数文件都是冗余的,将永远无法使用。所有Dojo版本都附带所有Dojo文件的完整副本,并且一个定制的dojo.js文件,其中结合了一些更常用的文件,减少加载成本的最佳方法是使用正确的Dojo构建。

dojo.js激活Dojo对象并动态加载其余模块,除非它们已由dojo.js的可选部分加载。 当浏览器首次加载dojo.js文件时,它将上传并设置以下文件:

  • Dojo引导程序代码
  • 道场装载机
  • 常用模块

为了减少加载时间,请考虑哪种版本最适合您的应用程序。 否则,您必须执行定制的Dojo构建。 有关Dojo文档的更多信息,请参见“ 相关主题”部分。

解析费用

为了最大程度地减少您的Dojo小部件解析成本,请使用以下两种方法之一来优化初始化:

标签实例化
您可以通过添加属性dojoType来创建带有HTML标记的Dojo小部件,如清单10所示。 此方法的前提是dojo.parser被包含在dojo.require("dojo.parser");djConfig="parseOnLoad:true" 。 这是用轻量级代码声明组件的简便方法。 加载文档后,将自动分析页面中具有dojoType属性的每个标记。 此方法对小型应用程序非常方便,但是对于具有大量HTML的Web应用程序,它可以显着增加启动时间。 解析器将访问每个元素,以检查是否必须对其进行解析。 使用配置文件,例如Firebug随附的配置文件。

如果发现在dj_load_init(),modulesLoaded()或类似初始加载的其他东西上花费了很多时间,请考虑对小部件进行初始化。

清单10.使用dojoType创建一个Dojo小部件
id="errorDialog" dojoType="dijit.Dialog" title='dialog1' class="pop-window"/>
代码实例化
Dojo是一个OOP框架,因此您可以使用new创建一个小部件。 要创建小部件,您必须输入两个参数:具有属性的JSON对象和要解析的元素。 每个小部件至少需要两个句子。 清单11中显示了一个示例。
清单11.使用JavaScript创建Dojo小部件new
new dijit.Dialog({"title":"dialog1 "},dojo.byId("dialog1"));

提升解析性能

为了优化代码结构和性能,请在创建窗口小部件时考虑促进解析。 通过将parseWidgets设置为false来禁用自动解析,然后创建一个数组以设置元素的ID,如清单12所示。 您还可以在运行时动态推送新元素的ID。 加载文档时,使用dojo.forEach()解析数组中的所有元素。

清单12.使用迭代的searchIds解析小部件
<head>
....
<script > djConfig = { parseWidgets: false, searchIds: [..] }; </script>
....
</head>
<body onload='dojo.forEach(djConfig.searchIds, 
   function(id){dojo.parser.parse(dojo.byId(id));});'>
........
</body>

解决方案

Dojo网格的性能问题主要涉及输入/输出操作,海量数据访问以及浏览器进行的数据渲染。 通过将几种机制与网格功能结合使用,可以提高Dojo网格小部件的性能。

查看您对缓存机制的使用。 当数据从数据库加载到本地时,请将数据保留在内存中很长时间。 这是减少从服务器端请求数据的时间响应的好方法。 在用户更新或修改网格中的数据之前,您不会向服务器端发送请求。 缓存机制大致由Dojo网格本身实现,但是当用户在网格上执行某些操作时会出现问题。 以下情形说明了此类问题:

排序网格
在大多数情况下,您可以正确地对网格进行排序,因为网格本身在数据存储级别实现了排序功能。 但是,数据存储反映了缓存。 例如,如果网格列的类型是汉字,则排序活动将产生错误的结果,并且由于不确定的因素,网格的性能将很差。

解决方案是在数据存储级别自己重新定义排序功能。 下面的清单13清单14显示了如何执行此操作:基于onHeaderCellMouseDown函数重写排序逻辑,呈现数据,并更新网格的标题视图。

清单13.重新定义排序逻辑
grid.onHeaderCellMouseDown = function(event){
	var items = DataStore.data.items;
//Sort the "Name" column which might contain characters like Chinese and so on
	if (event.cellIndex == 1) {
		sortAscending = ! sortAscending ;
//Change the string to localestring before comparison with localeCompare method
		if (sortAscending) {
			items.sort(function(m, n){
				return m["name"].toString().
				localeCompare(n["name"].toString());
			});
		}else {
			items.sort(function(m, n){
				return n["name"].toString().
				localeCompare(m["name"].toString());
			});
		}
	}else 
	//Sort the "Date" column
	if (event.cellIndex == 2) {
		sortAscending = !sortAscending;
		//Compare the date with milliseconds computed from 1970/07/01
		if (sortAscending) {
			items.sort(function(m, n){
			    return  Date.parse(m["date"].toString())
				 - Date.parse(n["date"].toString());
			});
		}else {
			items.sort(function(m, n){
				return Date.parse(n["date"].toString()) 
				- Date.parse(m["date"].toString());
			});
		}
	}
}
清单14.渲染数据,更新网格的标题视图
//"sorColIdx" is the index of the column to be sorted 
updateGridAfterSort : function(sortColIdx){
	//Render the data of the grid
	var store = new dojo.data.ItemFileWriteStore(DataStore.data);
	grid.setStore(store, null, null);
	grid.update();
	//Update the header view of the gird
	var headerNodeObjs = document.getElementsByTagName("th");
	for (var i = 0; i < 2; ++i) {
//"gridLayout" is a global array defining the layout of the grid
		var headerNodeObjName = gridLayout[0].cells[0][i].name;
		var headerNodeHtml = ['<div class="dojoxGridSortNode'];
		if (i == sortColIdx){
			headerNodeHtml = headerNodeHtml.concat([' ', (sortAscending ==
			 true) ? 'dojoxGridSortUp' : 'dojoxGridSortDown', '"><div 
			 class="dojoxGridArrowButtonChar">', (sortAscending == true) ? 
			 '▲' : '▼', '</div ><div class="dojoxGridArrowButtonNode"
			  ></div >']);
			headerNodeHtml = headerNodeHtml.concat([headerNodeObjName, 
			'</div>']);
			headerNodeObjs[i].innerHTML = headerNodeHtml.join(" ");
			break;
		}
	}
}
搜索网格
当网格具有海量数据时,搜索功能将导致性能下降,尤其是当网格可能支持实时搜索和模糊匹配功能时。 解决方案是在将数据转换为数据存储中使用的JSON对象之前,使用额外的内存空间来缓存数据。 这样可以避免很多函数调用,例如数据存储区的getItem清单15显示了一个示例。
清单15.从数组中的数据库中获取的缓存数据并进行搜索
//Fetch data from database
getData : function() {
	function callback(ResultSet) {
//ResultSet is an array of records fetched from database and make variable
//rawData refer to it to cache it in memory  
		GlobalVaribles.rawData = ResultSet;
//Convert the raw data ResultSet to JSON for data store use 	
		GlobalVaribles.dataJSON = JSONUtil.convert2JSON(ResultSet);
	}
	DBUtil.fetchAll(callback);
}
//Search functionality
search: function(col, value){
	if (value == null || value == "") {
		return;
	}
//Used here
	var rawData = GlobalVaribles.rawData;
	var newResults = [];
	for (var i = 0; i < rawData.length; i++) {
		var result = rawData[i];
//Fuzzy match
		if(result[col].toLowerCase().indexOf(value.toLowerCase()) != -1){
			newResults[newResults.length] = result;
		}
	}
//Render the new results
	GridManager.renderNewResults(newResults);
}
延迟加载机制
Dojo网格旨在支持延迟加载机制,从而提高了性能并提供了更好的用户体验。 Dojo网格中的延迟加载意味着在数据存储中呈现一些数据,但不是全部。 直到拖动滚动条,网格才会显示剩余数据。

默认情况下,网格不会打开延迟加载机制。 您必须明确启动它。 清单16显示了如何以两种不同的方式启动它。 rowsPerPagekeepRows属性是关键组件。

清单16.启动延迟加载机制
//The programmatic way
	            var grid = new dojox.grid.DataGrid({
	            store: store, //data store
	structure: gridLayout, 
	rowsPerPage: 10,  //Render 10 rows every time
	keepRows: 50,		//Keep 50 rows in rendering cache
}, "grid");   
//The declarative way using HTML label
<table  
dojoType="dojox.grid.DataGrid"
	id="grid" store="store" structure="gridLayout"
	query="{ id: '*' }" 
	rowsPerPage="10" keepRows="50">
	<!--  other definitions  -->
</table>
预载机制
即使用户可能只是临时需要它们,预加载机制也会提前加载剩余数据。 对于Dojo网格,数据存储区中可能有大量数据;例如, 用户可以拖动滚动条以查看剩余数据。 如果一页中有很多数据,那么仅查看特定的一行是不方便的。 使用预加载机制和分页技术可获得更方便的视图(类似于Google的分页栏)和更好的性能。

清单17显示了使用分页技术的基本实现。 首先,构造数据存储区用于初始分页栏的几个JSON对象,然后在用户单击分页栏的最后一页时动态添加一些新的JSON对象。

清单17.最初构造几个JSON对象并按需切换它们
//Fetch data from database and convert them to JSON objects
getData : function() {
	function callback(ResultSet) {
		GlobalVaribles.rawData = ResultSet;
//"convert2JSONs" method convert the raw data to several JSON objects
//stored in Global array "dataJSONs".
		GlobalVaribles.dataJSONs = JSONUtil.convert2JSONs(ResultSet);
	}
	DBUtil.fetchAll(callback);
}
//Initial status 
var dataStore = new dojo.data.ItemFileWriteStore({data:GlobalVaribles.dataJSONs[0]});
var grid = new dojox.grid.DataGrid({
	store: dataStore ,
	structure: gridLayout,
}, "grid");
grid.startup();
//Assuming that the user clicks the i-th item in the paging bar, we just update the data  
//store for the grid simply and the performance is still very good.
dataStore = new dojo.data.ItemFileWriteStore({data:GlobalVaribles.dataJSONs[i-1]});
grid.setStore(dataStore, null, null);
grid.update();

摘要

在本文中,您学习了如何确定Web应用程序中的几个问题或瓶颈。 现在,您可以使用几种工具,技巧和提示来调整和提高用户的性能。


翻译自: https://www.ibm.com/developerworks/web/library/wa-webappperformance/index.html

web应用程序和web网站

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值