提升 web 应用程序的性能

PostGIS空间分析在政务用地合规智能预检中的实践 空间分析是地理信息系统(GIS)的核心功能,它通过叠加、相交、缓冲等运算,揭示地理要素间的空间关系与模式。其原理基于计算几何与拓扑学,将现实世界抽象为点、线、面等几何对象进行处理。这项技术的价值在于将复杂的地理规则转化为可计算、可自动化的流程,极大提升了空间决策的效率与科学性。在工程实践中,空间分析广泛应用于国土规划、应急管理、智慧城市等领域,用于解决诸如选址分析、规划符合性审查等实际问题。本文以国土空间规划中的用地合规性智能预检为具体场景,深入探讨了如何利用PostGIS等开源技术构建高并发、高可用的空间 阅读详情

提升 web 应用程序的性能

找出瓶颈,加快客户端内容的速度

Luo Ling, 软件工程师, IBM
Zhong Chen, 开发人员, IBM
Mu Qiao Pan, 实习生, IBM
Yao Huang, I/T 专家, IBM
Ling Xiao Sun, 实习生, 南京大学

简介: 作为 web 用户,我们知道页面加载或刷新的速度对其成功至关重要。本文将帮助您更好地理解影响 web 应用程序性能的因素。学习识别这些问题并且找到客户端内容的瓶颈。探索 JavaScript、DOM、CSS 和 Dojo 小部件的性能问题。将通过一个例子展示使用 YSlow 和 Firebug 适当调整 Dojo 小部件。

原文链接:http://www.ibm.com/developerworks/cn/web/wa-webappperformance/index.html

 
   
 

 


概览

Rich Internet applications (RIAs) 在 Web 2.0 领域非常流行。为了提供新鲜、别致的用户体验,很多网站用 JavaScript 或 Flash 将复杂的内容从后台服务器搬到前台客户端。如果 数据较少的话,这提供了一个方便、新颖,流畅的用户界面(UI)。如果要将大量内容从服务器转移到客户端并在浏览器呈现,性能将显著下降。挑战是找到瓶颈,确定解决方案。

在浏览器中调整性能问题比在 Java 应用程序中更难。开发人员在各种浏览器中调试 JavaScript 的方法要少得多。在 Mozilla Firefox 中,可以使用 Firebug 调试 JavaScript,但仍然不能调整很多性能问题,如浏览器呈现消耗时间。为了解决这些问题,有必要开发浏览器插件来监控时间响应,以及确定其他对应解决方案如部分呈现或延时加载。

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

JavaScript 和 HTML DOM

JavaScript 是用在 Internet 上的最流行的脚本语言。数以万计的 web 页面设计师使用 JavaScript 来改善设计、验证表单、检查浏览器以及创建 cookie。HTML Document Object Model (DOM) 定义了访问和操作 HTML 文档的标准方法。它将 HTML 文档表示成节点树,其中包含元素、属性和文本内容。

通过使用 HTML DOM,JavaScript 能访问 HTML 文档中所有节点并操作它们。很多主流浏览器都支持 JavaScript 和 HTML DOM,而且很多网站也使用它们。它们使用的性能显著影响到整个 RIAs 的性能。

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. 作用域链结构
理解作用域链的结构对利用它很重要 

使用局部变量比使用全局变量快得多,因为在作用域链中越远,解析越慢。

如果代码中有 with 或 try-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 性能的内容。

重绘(Repaint)

当之前不可见的内容变得可见,DOM 就会重绘,反过来也一样。重绘也称为重画。此行为不会改变文档布局。不改变元素尺寸、形状或位置,只改变外观也会触发重绘。

例如,给元素添加边框或改变背景色就会触发重绘。重绘的性能代价很大;它需要引擎搜索所有元素以确定哪些可见,哪些必须显示。

回流(Reflow)

回流是比重绘更显著的改变。在回流中:

  • 要操作 DOM 树。
  • 影响布局的样式会改变。
  • 元素的 className 属性会改变。
  • 浏览器窗口尺寸改变。

引擎将会对相关元素回流,以确定各部分显示在哪。子元素也会被回流以反映父元素的新布局。DOM 中元素后面的元素也会被回流,以计算新布局,因为它们可能在初始回流时被移动了。祖先元素也会因子孙元素大小变化而被回流。最后,所有内容都被重绘。

每次向文档添加一个元素,浏览器都要回流页面来计算所有内容如何定位、如何呈现。添加的东西越多,回流次数越多。如果能减少单独添加元素的次数,浏览器回流次数就更少,运行也更快。

CSS 性能

将 Cascading Style Sheets (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 标签库来合并 JavaScript 和样式表文件。(pack:Tag 是一个 JSP-Taglib,可缩减、压缩及合并资源,如 JavaScript 和 CSS,并将它们在内容或普通文件中缓存。)
  • 使用 CSS Sprites。将背景图片合并成一个图片,并使用 CSS background-image 和 background-position 属性来显示所需图片部分。还可使用内联图片减少请求数。

后置加载组件

只呈现需要的组件;其余可等待。最好不要一次呈现太多组件。

某些情况下,可使用后置加载。由于浏览器可视区域外的组件可以后置加载,当这些组建进入可视区域不久后,初始呈现就会失效。

有些 JavaScript 可以在 onload 事件后后置加载,如 JavaScript 中初始呈现后拖动某个元素。

前置加载组件

通过前置加载组件,可以利用浏览器的空闲时间请求将来会用到的组件(如图像、样式和脚本)。当用户访问下个页面时,如果大多数组件都已在缓存中加载,那页面加载会快得多。

有两种前置加载:

  • 无条件:一旦触发 onload,就取得一些额外组件。
  • 有条件:根据用户的动作,推测用户下一步的方向并进行相应的前置加载。

将脚本放在底部

脚本可能会产生问题,因为它们可能会阻碍并行下载。当下载脚本时,浏览器不会再启动其他下载 — 即使那些位于不同主机。将脚本,如样式表,放在底部,以保证它们在其他下载完成后再下载。

也可以使用延时脚本,这只有 Internet Explorer 支持。DEFER 属性表示脚本不含 document.write()。这就告诉浏览器他们可以持续呈现。

使用无 cookie 域组件

当浏览器发出对静态图片的请求,并随之发送 cookie 时,服务器不会使用那些 cookie。由于这些 cookie 只会造成不必要的网络流量,确保用无请求来请求静态组件。然后使用子域和主机保存这些静态组件。

将 JavaScript 和 CSS 放在外部

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

RIA 小部件性能

主流 RIA Ajax 框架,如 ExtJS、YUI、Dojo 及其他,都提供一些精巧的小部件库,以增强用户体验。与其他框架相比,Dojo 在企业开发领域更强大,这是由于:

  • Object-oriented programming (OOP) 编码
  • 跨平台
  • 本地数据存储的 Dojo 离线 API 支持
  • DataGrid、2D 和 3D 图形(图表组件提供了在浏览器展示报表更简单的方法)

Dojo 在很多网站广泛使用。我们将使用 Dojo 举例,分析 RIA 小部件的性能。可根据具体情况使用 Dojo 小部件调整工具,有 Page Speed、Rock Star Optimizer 及 Jiffy。我们强烈建议使用 YSlow 和 Firebug。

YSlow

YSlow 根据一组高性能 web 页面准则,通过检查页面上所有组件,包括由 JavaScript 创建的,来分析 web 页面性能。YSlow 是一个集成了 Firebug web 开发工具的 Firefox 插件;它可提供提升页面性能的建议、总结组件性能、显示页面统计数据并提供用于性能分析的工具。

图 3 显示的是 YSlow Grade 选项卡上的信息。


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

YSlow 的 web 页面建立在 22 条可测试的规则基础上,这些规则在下方按重要性和效果排列。研究显示,按照以下规则,web 页面响应时间可提升 25% 到 50%:

  • 尽量减少 HTTP 请求数。
  • 使用内容发布网络(CDN)。
  • 添加 Expires 或 Cache-Control 头部。
  • 用 Gzip 压缩内容。
  • 将样式表放在顶部。
  • 将脚本放在底部。
  • 避免使用 CSS 表达式。
  • 将 JavaScript 和 CSS 放在外部。.
  • 减少 DNS 搜索。
  • 精简 JavaScript 和 CSS。
  • 避免使用重定向。
  • 删除重复的脚本。
  • 配置 ETags。
  • 使 Ajax 可缓存。
  • 使用 GET 进行 Ajax 请求。
  • 减少 DOM 元素数。
  • 消除 404 错误。
  • 减小 cookie 大小。
  • 对组件使用无 cookie 的域。
  • 避免使用过滤器。
  • 不在 HTML 中测量图片大小。
  • 使 favicon.ico 尽可能小,可缓存。

图 4 中的 YSlow Statistics,对空缓存的访问用户和之前访问过页面的用户的页面大小做了对比。


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

Components 选项卡显示了每个组件及相关的性能信息。例如,如果组件被 gzip 压缩,或 ETag 有内容(如果的话),您都能看到。组件大小和超期时间也显示在 Components 选项卡中,如 图 5 所示。


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

Firebug

Firebug 与 Mozilla Firefox 集成,使您在浏览网站时有大量开发工具随手可用。可以即时编辑、调试、监控 web 页面中的 CSS、HTML 和 JavaScript。

可以使用 Firebug Net 面板,如 图 6 所示,监控 web 页面产生的 HTTP 流量。它向用户展示了所有收集到的和计算出的信息。每个条目表示页面的一个请求/响应来回。


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

Firebug Console 面板,如 图 7 所示,提供了两种监控代码性能的方法。


图 7. Firebug Console 面板
The Firebug Console 面板帮助监控代码性能 
Profile
对于某个特定的函数,使用 Profiler。JavaScript Profiler 是能用来测量每个 JavaScript 代码执行时间的 Firebug 特性。使用 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 小部件性能的方法。

加载成本

如 “Improving performance of Dojo-based web applications" (E. Lazutkin, Feb 2007)中所指出,大多数 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 文档信息,见 参考资料 一章。

解析成本

为了最小化 Dojo 小部件解析成本,使用以下两个方法来优化初始化:

Tag 实例化
可以通过添加  dojoType 属性创建一个带有 HTML 标签的 Dojo 小部件,如  清单 10 所示。此方法运行的前提是 dojo.parser 包含在  dojo.require("dojo.parser"); 中,并且  djConfig="parseOnLoad:true"。这是个很简单的方法,可在轻量级代码中声明组件。页面中所有具有  dojoType 属性的标签都会在文档加载后自动解析。该方法对小型应用程序非常方便,但会显著增加具有大量 HTML 的 web 应用程序的启动时间。解析器将访问所有元素,检查是否要解析。使用配置文件,如 Firebug 中所提供的。

如果发现在 dj_load_init()、modulesLoaded() 或其他类似初始装载的内容上花费过多时间,就考虑小部件初始化。


Listing 10. 创建 dojoType 的 Dojo 小部件

							
id="errorDialog" dojoType="dijit.Dialog" title='dialog1' class="pop-window"/>

代码实例化
Dojo 是一个 OOP 框架,因此可以使用  new 创建小部件。要创建小部件,必须输入两个参数:一个具有属性的 JSON 对象和要解析的元素。每个小部件至少需要两个语句。 清单 11 是一个样例。


清单 11. 用 JavaScript new 创建一个 Dojo 小部件

							
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 οnlοad='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 演示了用两种方法启动。rowsPerPage 和 keepRows属性是关键组件。


清单 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://i-blog.csdnimg.cn/blog_migrate/278e71e26b091bdf93ac44318dc5d0bb.jpeg

Luo Ling 是 Dojo 开发和可访问性技术的专家。

https://i-blog.csdnimg.cn/blog_migrate/2cc2ec127b63ee36d666fd6510ef8a1f.jpeg

Chen Zhong 是 IBM China Development Lab 的开发人员。他有数年 J2EE 开发经验。

https://i-blog.csdnimg.cn/blog_migrate/205781766c4e8f0626af904f96787956.jpeg

Pan Qiao Mu 来自浙江大学。他是位于上海的 IBM China Development Lab 的 UT 部门的实习生。他的研究兴趣包括计算机图形处理和 Web 2.0。

https://i-blog.csdnimg.cn/blog_migrate/137b5a27200c7c8f39d5550c9759d9bd.jpeg

Yao Huang 是 RIAs 和 web 用户界面技术的专家。

https://i-blog.csdnimg.cn/blog_migrate/6d728739bd52dddee98f5bfe11068070.jpeg

Sun Xiao Ling 是位于上海的 IBM China Development Lab 的实习生。

postgis不同的栅格存储方式和查询的速度以及区域统计 很多应用都需要综合处理栅格和矢量数据进行统计,如果两者在同一个数据库里就很方便。 但是有些影像太大了,而且还经常得更新,所以我这次想用文件式的管理,只把索引入库,一查postgis是支持这种的。 raster2pgsql -s 3857 -R -C -I -M -F "raster.tif" -t 50x50 public.tablename |psql -U postgres -d da... 阅读详情

相关推荐

PostGIS空间数据库实战:从零构建海域监测数据管理系统

空间数据是描述物体位置、形状及其空间关系的信息,在GIS、物联网和位置服务中广泛应用。其核心原理是通过点、线、面等几何对象及空间参考系统对现实世界进行建模。PostGIS作为PostgreSQL的空间扩展,提供了原生空间数据类型、丰富空间函数和高效空间索引,解决了传统关系型数据库处理空间查询的瓶颈。这一技术方案特别适用于需要处理海量时空数据的场景,如环境监测、轨迹分析和地理信息服务。本文以海域污染监测为具体案例,详细展示了如何利用PostGIS构建完整的数据管理技术栈,涵盖从数据库设计、空间查询到Pytho

weixin_30851867的博客 319

常见Web性能瓶颈及分析

常见Web性能瓶颈及分析.pdf

Cesium+OpenLayers+PostGIS:智慧公交站点二维采编与三维展示实践

在WebGIS项目开发中,如何让二维地图数据与三维大屏无缝衔接,是许多工程团队面临的真实痛点。本文以智慧公交站点系统为案例,详细解析Cesium负责三维大屏渲染、OpenLayers承担二维地图交互采编、PostGIS提供空间数据存储与覆盖分析的技术组合方案。从空间数据库的建模设计、坐标系与投影的转换,到缓冲区覆盖分析、GeoJSON数据接口联调,完整展示了从数据录入、空间计算到三维可视化的链路。这套开源技术栈不仅解决了公交站点500米覆盖范围计算、服务半径模拟等实际业务需求,也为智慧园区、智慧水务等同类项

weixin_34234721的博客 435

提升 web 应用程序的性能---http://www.ibm.com/developerworks/cn/web/wa-webappperformance/index.html

概览 Rich Internet applications (RIAs) 在 Web 2.0 领域非常流行。为了提供新鲜、别致的用户体验,很多网站用 JavaScript 或 Flash 将复杂的内容从后台服务器搬到前台客户端。如果 数据较少的话,这提供了一个方便、新颖,流

jyb123的专栏 1683

GIS空间分析实战:从数据处理到选址建模的完整Python工作流

地理信息系统(GIS)是处理和分析空间数据的核心技术体系,其核心原理在于将现实世界的地理要素抽象为矢量(点、线、面)和栅格数据模型,通过坐标参考系统进行精准的空间定位。这项技术的价值在于能够将抽象的地理信息转化为可量化、可分析的结构化数据,从而支持空间关系查询、缓冲区分析、叠加分析等复杂运算。在工程实践中,GIS广泛应用于城市规划、环境监测、物流优化和商业选址等场景。本文聚焦于智慧城市项目中的设施选址问题,通过Python生态中的GeoPandas、Shapely等工具链,系统演示如何将原始地理空间数据转化

weixin_30800987的博客 377

别再死记硬背了!一张图搞懂PostGIS的17种geometry类型(附SQL实操)

本文通过可视化方式详细解析PostGIS中的17种geometry类型,包括基础的点、线、面以及高级曲线类型如CircularString和CompoundCurve。附赠实用的SQL代码片段,帮助开发者快速掌握空间数据模型,提升地理信息处理效率。

weixin_30847865的博客 346

Web客户端遇到的10个影响性能的突出问题

<br /> #1 调用数据库过多 <br />     我们见到的最多的问题是,每次请求或事务,查询数据库的次数太多。这有3种特殊的现象来证实。 <br />在当前事务的上下文中,请求的数据多于实际需要的数据。例如:请求所有用户信息而不是那些我们要显示到<br />当前屏幕的信息。 <br />同样的数据被请求多次。这通常发生在不同的组件在同一个事务中彼此独立的调用,并且每次都请求同类数据<br />。因为不知道哪种类型的数据已经加载到当前的上下文中,最终导致多次相同的查询。 <br />为了取得一特定的

changjianghoulang168的专栏 846

PostGIS vs GeoTools:处理自相交多边形的两种实战方案对比

本文深入对比了PostGIS和GeoTools处理自相交多边形(Self-Intersecting Polygon)的两种技术方案。通过分析两者的核心算法、性能表现和适用场景,为开发者提供在不同技术栈中选择最佳解决方案的实用指南,帮助高效解决空间数据中的拓扑问题。

weixin_29198045的博客 424

web服务器性能瓶颈,Web服务器性能瓶颈因素

Web服务器性能瓶颈因素五、Web服务器Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件发送到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)进行信息交流,这就是人们常把它们称为HTTPD服务器的原因。Web服务器Web服务器不仅能够存储信息,还能在用户通过Web浏览...

weixin_28872283的博客 809

AI如何真正理解城市:数据清洗、空间语义建模与规划决策闭环

城市智能规划本质上是将多源异构城市数据(如POI、信令、路网)转化为可解释、可验证、可行动的空间决策依据。其核心原理在于突破传统GIS的几何分析局限,构建融合物理约束、社会感知与动态交互的三维空间语义模型;技术价值体现在以轻量化开源栈(Python+PostGIS+QGIS)实现高合规性、低门槛、强落地的分析闭环;典型应用场景包括职住平衡诊断、十五分钟生活圈评估、公交接驳优化等;关键成败线不在算法复杂度,而在于数据清洗的真实性校验、空间建模的本体逻辑对齐,以及结果验证从‘模型准确率’转向‘规划师点头率’——

ctk87443的博客 597

土地利用变化监测模拟

准备 postgis数据库(下载安装指导点这里) 注:需要具备基础数据库操作知识和基础gis空间运算知识(简单基础) 思路讲解 假设ABCD四种类型,变化前后如下图所示 简单分析 变化的地块应为 数据录入 变化前数据 变化后数据 交集运算 SELECT st_intersection(l08.geom, l10.geom) AS "intersect", l08."landUseType" AS before, l10."landUseType" AS after FROM

qq_39014170的博客 339

Web应用的性能优化思路——瓶颈

原文: http://www.oschina.net/bbs/thread/8639   瓶颈是什么? 一条4车道的公路,运行非常顺畅,突然出了点事故,事故车导致某个地方只剩下1车道,然后就开始堵车,因为四辆车同时塞向一个车道里。把这个事故清除了,故障车拖走了,道路会开始恢复了通畅。 这个道理谁都懂,但偏偏有些傻瓜交警去把4车道变成8车道,但却不清理事故路段。 一个Web应用,不管是何...

cm00337533的专栏 424

postgis修复几何,修复自相交

1、报错问题 一般进行空间查询分析的时候,数据库报错如下: NOTICE: Ring Self-intersection at or near point 98.56186929203426 25.024940000380752 NOTICE: Ring Self-intersection at or near point 98.840470640108038 24.256657960096845 NOTICE: Ring Self-intersection at or near point 101.

polixiaohai的专栏 3759

GIS开发全解析:从技术栈到职业路径,构建空间世界的代码实践

地理信息系统(GIS)开发是融合地理空间数据与软件工程的交叉领域,其核心在于将空间数据产品化与服务化。从技术原理看,它依赖于空间数据库(如PostGIS)进行高效的空间查询与分析,并遵循OGC标准(如WMS、WFS)实现服务的互操作。在工程实践中,GIS开发的价值在于解决复杂的空间计算问题,并将其转化为高性能、可扩展的应用。这要求开发者不仅掌握编程语言(如Python、JavaScript)和数据库技术,还需深入理解空间索引、地图服务发布与优化等核心概念。其应用场景广泛,涵盖智慧城市、互联网LBS、自然资源

weixin_34384557的博客 368

Voronoi算法在游戏开发与GIS中的实战应用与对比

Voronoi图,又称泰森多边形,是一种基于距离的空间划分算法,其核心原理是将平面划分为多个区域,确保每个区域内的点到其对应种子点的距离最近。这种划分方式在计算几何和空间分析中具有重要价值,广泛应用于需要模拟自然生成、划分势力范围或服务区的场景。在游戏开发领域,Voronoi算法常用于程序化生成地形、模拟细胞分裂或创建领土系统,以增强视觉效果和游戏性;在地理信息系统(GIS)中,它则是设施服务区分析、商圈辐射范围划定等空间分析任务的核心工具。本文聚焦于Voronoi算法在Unity游戏引擎与GIS平台中的实

weixin_30883311的博客 353

AI城市规划实战:从大数据到15分钟生活圈落地

城市智能规划是融合地理信息系统、时空大数据与可解释AI的城市治理新范式,其核心在于将模糊的经验判断转化为可验证、可迭代的量化决策证据链。通过移动信令、POI、政务及IoT等多源数据融合建模,结合图神经网络(GNN)动态OD分析、PostGIS空间合规校验与SHAP可解释性输出,系统支撑交通流量预测、公共设施选址、用地优化等关键任务。技术价值不仅体现于模型精度,更在于驱动规划流程从‘经验驱动’转向‘证据驱动’,实现如‘15分钟社区生活圈’这类法定指标的精准评估与闭环优化。本文聚焦真实项目中数据清洗、模型泛化与

weixin_30839881的博客 453

瓦片地图实战指南:从地理数据聚合到业务可读可视化

瓦片地图是一种以空间单元为最小信息载体的栅格化地理表达方式,其核心原理是将连续地理空间离散为规则网格,并在每个网格中聚合可解释、可行动的业务指标。相比传统点图或热力图,它通过边界明确的视觉原子单位,显著提升人眼对空间差异的感知效率与业务解读准确性。技术价值体现在三方面:规避点重叠遮蔽、支持多维指标绑定、保障跨区域数据可比性。典型应用场景包括零售热力归因、物流时效监控、城市网格化运营等。本文聚焦如何基于真实GPS数据,完成从清洗、空间纠偏、动态聚合到GeoJSON瓦片生成与前端交互渲染的全链路落地。

cok8420的博客 479

S7-1200PLC期末复习题(第七章)

A.0 B.1 C.4 D.-4 A、CV = 0 B、CV = 1 C、CV < 4 D、CV >= 4A、0,0 B、3,0 C、1,1 D、3,1 A、0 B、1 C、先是1,再变为0 D、先是0,再变为1置位输出:常开触点M0.0闭合,Q0.0变为1状态并保存该状态,即使M0.0断开,Q0.0也保持1状态。 复位输出:常开触点M0.1闭合时,Q0.0变为0状态并保持该状态,即使M0.1断开,Q0.0也保持为0状态。 A、1 B、0 C、5 D、10RESET_BF指令需要两个参数,第一个是复位的位数

qq_52251819的博客 4421
上一篇: JavaScript 框架比较
下一篇: 提高 web 应用性能之 JavaScript 性能调优
wolfman79
博客等级 码龄24年 25粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值