如果在JSP页面中要访问2017年廷迟退休政策加载的数据, 如何处理

3645人阅读
JAVA_WEB(14)
1: Oneto Many,默认是采用延迟加载的(lazy=true),因为很多情况下,当我们获取到One的一方后,Many的一方并非立即需要的,当我们经常只需要One的一方的时候,延迟加载就很有意义了.
2:Hibernate 中的延迟加载(lazy loading),当我们在程序中获取到了一的一方,但是不需要多的一方,那么使用延迟加载就是非常适合的.
3:当我们One和Many都要同时需要的时候,我们可以将One的一方的hbm.xml中用于保存Many的Set元素的lazy改为false
One to Many的延迟加载分析
当我们通过通过Session.get()查询到One的一方后,其中用于保存Many的Set其实是一个代理,其类型为org.hibernate.collection., PersistentSet
实现了Java.util.Set接口,并内置了一个用于存放实际数据的HashSet,初始时为空,当真正要访问这个集合的元素时,如调用Java.util.Set#iterator()#toArray() #containsAll(),#toString,#equal()#hashCode等要真正访问集合的元素的方法的时候,程序才主要发出SQL语句,真正加载Many一方,并且一次读取完Many一方的所有元素.
PersistentSet 实现了Java.util.Set接口,并内置了一个HashSet实例,PersistentSet代理了Java.util.Set的#iterator()#toArray()
#containsAll(),#toString等方法: 而代理的过程很简单:&
若要访问到Many的数据,则先加载Many的所有元素,再简单调用被代理的方法!
这里也是应用到&代理模式&的思想..框架里,这个模式很常用......
在Hibernate里,延迟加载基本是用&代理模式&实现的!
public class PersistentSet extendsAbstractPersistentCollection implements java.util.Set {
。。。。。。。。。。。。。。
publicString toString() {
//先加载Many一方
return set.toString();
。。。。。。。。。。。
再看看read()方法:
public abstract classAbstractPersistentCollection implementsSerializable, PersistentCollection {
…………………………………
* Called by any read-only method of the collection interface
protected final void read() {
initialize(false);
protectedfinal void initialize(boolean writing) {
if (!initialized) {
if(initializing) {
throw new LazyInitializationException(&illegal access toloading collection&);
//检查与数据库的连接
throwLazyInitializationExceptionIfNotConnected();
//这里真正加载Many
session.initializeCollection(this, writing);
…………………………………….
Order&& &-&& many-to-one&&-&Customer&&
在Many.hbm.xml中
&many-to-one name=&customer&class=&beans.Customer& column=&customer_id& lazy=&false&&
&/many-to-one&
1.& lazy=&false&
false:取消懒加载策略,即在加载对象的同时,发出查询语句,加载其关联对象&
意为: 在Many一方中查询出一个对象之后,同时也要查出One的一方. One的一方的类型为One的实际类型(非代理类,这里是Customer)
=&proxy& //这是默认值
proxy:这是hibernate对单端关联的默认懒加载策略,即只有在调用到其关联对象的方法的时候才真正发出查询语句查询其对象数据,其关联对象是代理类&
意为: 在Many一方中查询出一个对象之后,One的一方用代理类代替(Customer_$$_javassist_1),这个代理只包含One的一方的ID,而这个ID是在Many这一方的标识One的外键,目的是为了延迟初始化One的一方.,当真正访问One的一方时,才正式初始化它.所以最终取得的是代理类(非实际的类型,初始化前只含Customer的ID)
3.lazy=&no-proxy&
&&&&&&&&&&&&&&&& 不常用…,那个” 编译时字节码增强”都不知道是什么了的…本人没有什么增强工具的情况,效果和proxy一样的,也是用代理类 Customer_$$_javassist_1 来代理了Customer对象,用反射分析到两种情况下的代理类的字段,方法都一样的…这个不管了..
网上的分析:
Child&& &-&& many-to-one&&-&Parent&&&
& class&& Child&&{&&&
&&&&& private&&Parent&&&&&
&&&&& public&&Parent&& getParent&& (){&&&
&&&&&&&&&return&& this.//访问了实例变量&&&
&&&&& }&&&
& class&& Parent&&{&&&
&&&&& private&&String&&&&&
&&&&& public&&String&& getName(){&&&
&&&&&&&&&return&& this.//访问了实例变量&&&
&&&&& }&&&
&&&&& public&&void&& f(){&&&
&&&&&&&&&System.out.println(&invokeing&& f()&);//没有访问实例变量&&&
&&&&& }&&&
& 如果&& many-to-one&& 的lazy设为proxy,当child.getParent().getName()或child.getParent().f()时,parent都会被抓取,若设为no-proxy,调用child.getParent().f()时,parent是不会被抓取的,同时这种方式需要编译时字节码增强,否则和proxy没区别。
--------------------------------------------------------------
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:192252次
积分:2262
积分:2262
排名:第13038名
原创:43篇
评论:35条
(1)(1)(1)(2)(1)(1)(4)(5)(3)(6)(14)(5)hibernate(5)
Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载。Hibernate 通过这种延迟加载来降低系统的内存开销,从而保证 Hibernate 的运行性能。
下面先来剖析 Hibernate 延迟加载的“秘密”。
当 Hibernate 从数据库中初始化某个持久化实体时,该实体的集合属性是否随持久化类一起初始化呢?如果集合属性里包含十万,甚至百万的记录,在初始化持久化实体的同时,完成所有集合属性的抓取,将导致性能急剧下降。完全有可能系统只需要使用持久化类集合属性中的部分记录,而完全不是集合属性的全部,这样,没有必要一次加载所有的集合属性。
对于集合属性,通常推荐使用延迟加载策略。所谓延迟加载就是等系统需要使用集合属性时才从数据库装载关联的数据。
例如下面 Person 类持有一个集合属性,该集合属性里的元素的类型为 Address,该 Person 类的代码片段如下:
public class Person
// 标识属性
// Person 的 name 属性
// 保留 Person 的 age 属性
// 使用 Set 来保存集合属性
private Set&Address& addresses = new HashSet&Address&();
// 下面省略了各属性的 setter 和 getter 方法
为了让 Hibernate 能管理该持久化类的集合属性,程序为该持久化类提供如下映射文件:
&?xml version=&1.0& encoding=&GBK&?&
&!DOCTYPE hibernate-mapping PUBLIC
&-//Hibernate/Hibernate Mapping DTD 3.0//EN&
&http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd&&
&hibernate-mapping package=&org.crazyit.app.domain&&
&!-- 映射 Person 持久化类 --&
&class name=&Person& table=&person_inf&&
&!-- 映射标识属性 id --&
&id name=&id& column=&person_id&&
&!-- 定义主键生成器策略 --&
&generator class=&identity&/&
&!-- 用于映射普通属性 --&
&property name=&name& type=&string&/&
&property name=&age& type=&int&/&
&!-- 映射集合属性
&set name=&addresses& table=&person_address& lazy=&true&&
&!-- 指定关联的外键列 --&
&key column=&person_id&/&
&composite-element class=&Address&&
&!-- 映射普通属性 detail --&
&property name=&detail&/&
&!-- 映射普通属性 zip --&
&property name=&zip&/&
&/composite-element&
&/hibernate-mapping&
从上面映射文件的代码可以看出,Person 的集合属性中的 Address 类只是一个普通的 POJO。该 Address 类里包含 detail、zip 两个属性。由于 Address 类代码非常简单,故此处不再给出该类的代码。
上面映射文件中 &set.../& 元素里的代码指定了 lazy=&true&(对于 &set.../& 元素来说,lazy=&true&是默认值),它指定 Hibernate 会延迟加载集合属性里 Address 对象。
例如通过如下代码来加载 ID 为 1 的 Person 实体:
Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction();
Person p = (Person) session.get(Person.class, 1);
System.out.println(p.getName());
上面代码只是需要访问 ID 为 1 的 Person 实体,并不想访问这个 Person 实体所关联的 Address 对象。此时有两种情况:
如果不延迟加载,Hibernate 就会在加载 Person 实体对应的数据记录时立即抓取它关联的 Address 对象。
如果采用延迟加载,Hibernate 就只加载 Person 实体对应的数据记录。
很明显,第二种做法既能减少与数据库的交互,而且避免了装载 Address 实体带来的内存开销——这也是 Hibernate 默认启用延迟加载的原因。
现在的问题是,延迟加载到底是如何实现的呢? Hibernate 在加载 Person 实体时,Person 实体的 addresses 属性值是什么呢?
为了解决这个问题,我们在&&1&号代码处设置一个断点,在 Eclipse 中进行 Debug,此时可以看到 Eclipse 的 Console 窗口有如图 1 所示的输出:
正如图 1 输出所看到的,此时 Hibernate 只从 Person 实体对应的数据表中抓取数据,并未从 Address 对象对应的数据表中抓取数据,这就是延迟加载。
那么 Person 实体的 addresses 属性是什么呢?此时可以从 Eclipse 的 Variables 窗口看到如图 2 所示的结果:
从图 2 的方框里的内容可以看出,这个 addresses 属性并不是我们熟悉的 HashSet、TreeSet 等实现类,而是一个 PersistentSet 实现类,这是 Hibernate 为 Set 接口提供的一个实现类。
PersistentSet 集合对象并未真正抓取底层数据表的数据,因此自然也无法真正去初始化集合里的 Address 对象。不过 PersistentSet 集合里持有一个 session 属性,这个 session 属性就是 Hibernate Session,当程序需要访问 PersistentSet 集合元素时,PersistentSet 就会利用这个 session 属性去抓取实际的 Address 对象对应的数据记录。
那么到底抓取那些 Address 实体对应的数据记录呢?这也难不倒 PersistentSet,因为 PersistentSet 集合里还有一个 owner 属性,该属性就说明了 Address 对象所属的 Person 实体,Hibernate 就会去查找 Address 对应数据表中外键值参照到该 Person 实体的数据。
例如我们单击图 2 所示窗口中 addresses 行,也就是告诉 Eclipse 要调试、输出 addresses 属性,这就是要访问 addresses 属性了,此时就可以在 Eclipse 的 Console 窗口看到输出如下 SQL 语句:
addresses0_.person_id as person1_0_0_,
addresses0_.detail as detail0_,
addresses0_.zip as zip0_
person_address addresses0_
addresses0_.person_id=?
这就是 PersistentSet 集合跟据 owner 属性去抓取特定 Address 记录的 SQL 语句。此时可以从 Eclipse 的 Variables 窗口看到图 3 所示的输出:
从图 3 可以看出,此时的 addresses 属性已经被初始化了,集合里包含了 2 个 Address 对象,这正是 Person 实体所关联的两个 Address 对象。
通过上面介绍可以看出,Hibernate 对于 Set 属性延迟加载关键就在于 PersistentSet 实现类。在延迟加载时,开始 PersistentSet 集合里并不持有任何元素。但 PersistentSet 会持有一个 Hibernate Session,它可以保证当程序需要访问该集合时“立即”去加载数据记录,并装入集合元素。
与 PersistentSet 实现类类似的是,Hibernate 还提供了 PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等实现类,它们的功能与 PersistentSet 的功能大致类似。
熟悉 Hibernate 集合属性读者应该记得:Hibernate 要求声明集合属性只能用 Set、List、Map、SortedSet、SortedMap 等接口,而不能用 HashSet、ArrayList、HashMap、TreeSet、TreeMap 等实现类,其原因就是因为 Hibernate 需要对集合属性进行延迟加载,而 Hibernate 的延迟加载是依靠 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet
来完成的——也就是说,Hibernate 底层需要使用自己的集合实现类来完成延迟加载,因此它要求开发者必须用集合接口、而不是集合实现类来声明集合属性。
Hibernate 对集合属性默认采用延迟加载,在某些特殊的情况下,为 &set.../&、&list.../&、&map.../& 等元素设置 lazy=&false&属性来取消延迟加载。
默认情况下,Hibernate 也会采用延迟加载来加载关联实体,不管是一对多关联、还是一对一关联、多对多关联,Hibernate 默认都会采用延迟加载。
对于关联实体,可以将其分为两种情况:
关联实体是多个实体时(包括一对多、多对多):此时关联实体将以集合的形式存在,Hibernate 将使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合来管理延迟加载的实体。这就是前面所介绍的情形。
关联实体是单个实体时(包括一对一、多对一):当 Hibernate 加载某个实体时,延迟的关联实体将是一个动态生成代理对象。
当关联实体是单个实体时,也就是使用 &many-to-one.../& 或 &one-to-one.../& 映射关联实体的情形,这两个元素也可通过 lazy 属性来指定延迟加载。
下面例子把 Address 类也映射成持久化类,此时 Address 类也变成实体类,Person 实体与 Address 实体形成一对多的双向关联。此时的映射文件代码如下:
&?xml version=&1.0& encoding=&GBK&?&
&!-- 指定 Hibernate 的 DTD 信息 --&
&!DOCTYPE hibernate-mapping PUBLIC
&-//Hibernate/Hibernate Mapping DTD 3.0//EN&
&http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd&&
&hibernate-mapping package=&org.crazyit.app.domain&&
&!-- 映射 Person 持久化类 --&
&class name=&Person& table=&person_inf&&
&!-- 映射标识属性 id --&
&id name=&id& column=&person_id&&
&!-- 定义主键生成器策略 --&
&generator class=&identity&/&
&!-- 用于映射普通属性 --&
&property name=&name& type=&string&/&
&property name=&age& type=&int&/&
&!-- 映射集合属性,集合元素是其他持久化实体
没有指定 cascade 属性,指定不控制关联关系 --&
&set name=&addresses& inverse=&true&&
&!-- 指定关联的外键列 --&
&key column=&person_id&/&
&!-- 用以映射到关联类属性 --&
&one-to-many class=&Address&/&
&!-- 映射 Address 持久化类 --&
&class name=&Address& table=&address_inf&&
&!-- 映射标识属性 addressId --&
&id name=&addressId& column=&address_id&&
&!-- 指定主键生成器策略 --&
&generator class=&identity&/&
&!-- 映射普通属性 detail --&
&property name=&detail&/&
&!-- 映射普通属性 zip --&
&property name=&zip&/&
&!-- 必须指定列名为 person_id,
与关联实体中 key 元素的 column 属性值相同 --&
&many-to-one name=&person& class=&Person&
column=&person_id& not-null=&true&/&
&/hibernate-mapping&
接下来程序通过如下代码片段来加载 ID 为 1 的 Person 实体:
// 打开上下文相关的 Session
Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction();
Address address = (Address) session.get(Address.class , 1); //&1&
System.out.println(address.getDetail());
为了看到 Hibernate 加载 Address 实体时对其关联实体的处理,我们在&&1&号代码处设置一个断点,在 Eclipse 中进行 Debug,此时可以看到 Eclipse 的 Console 窗口输出如下 SQL 语句:
address0_.address_id as address1_1_0_,
address0_.detail as detail1_0_,
address0_.zip as zip1_0_,
address0_.person_id as person4_1_0_
address_inf address0_
address0_.address_id=?
从这条 SQL 语句不难看出,Hibernate 加载 Address 实体对应的数据表抓取记录,并未从 Person 实体对应的数据表中抓取记录,这是延迟加载发挥了作用。
从 Eclipse 的 Variables 窗口看到如图 4 所示的输出:
从图 4 可以清楚地看到,此时 Address 实体所关联的 Person 实体并不是 Person 对象,而是一个 Person_$$_javassist_0 类的实例,这个类是 Hibernate 使用 Javassist 项目动态生成的代理类——当 Hibernate 延迟加载关联实体时,将会采用 Javassist 生成一个动态代理对象,这个代理对象将负责代理“暂未加载”的关联实体。
只要应用程序需要使用“暂未加载”的关联实体,Person_$$_javassist_0 代理对象会负责去加载真正的关联实体,并返回实际的关联实体——这就是最典型的代理模式。
单击图 4 所示 Variables 窗口中的 person 属性(也就是在调试模式下强行使用 person 属性),此时看到 Eclipse 的 Console 窗口输出如下的 SQL 语句:
person0_.person_id as person1_0_0_,
person0_.name as name0_0_,
person0_.age as age0_0_
person_inf person0_
person0_.person_id=?
上面 SQL 语句就是去抓取“延迟加载”的关联实体的语句。此时可以看到 Variables 窗口输出图 5 所示的结果:
Hibernate 采用“延迟加载”管理关联实体的模式,其实就在加载主实体时,并未真正去抓取关联实体对应数据,而只是动态地生成一个对象作为关联实体的代理。当应用程序真正需要使用关联实体时,代理对象会负责从底层数据库抓取记录,并初始化真正的关联实体。
在 Hibernate 的延迟加载中,客户端程序开始获取的只是一个动态生成的代理对象,而真正的实体则委托给代理对象来管理——这就是典型的代理模式。
代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上也不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(Proxy)。
在这种设计方式下,系统会为某个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个 Java 对象代表另一个 Java 对象来采取行动。在某些情况下,客户端代码不想或不能够直接调用被调用者,代理对象可以在客户和目标对象之间起到中介的作用。
对客户端而言,它不能分辨出代理对象与真实对象的区别,它也无须分辨代理对象和真实对象的区别。客户端代码并不知道真正的被代理对象,客户端代码面向接口编程,它仅仅持有一个被代理对象的接口。
总而言之,只要客户端代码不能或不想直接访问被调用对象——这种情况有很多原因,比如需要创建一个系统开销很大的对象,或者被调用对象在远程主机上,或者目标对象的功能还不足以满足需求……,而是额外创建一个代理对象返回给客户端使用,那么这种设计方式就是代理模式。
下面示范一个简单的代理模式,程序首先提供了一个 Image 接口,代表大图片对象所实现的接口,该接口代码如下:
public interface Image
void show();
该接口提供了一个实现类,该实现类模拟了一个大图片对象,该实现类的构造器使用 Thread.sleep() 方法来暂停 3s。下面是该 BigImage 的程序代码。
// 使用该 BigImage 模拟一个很大图片
public class BigImage implements Image
public BigImage()
// 程序暂停 3s 模式模拟系统开销
Thread.sleep(3000);
System.out.println(&图片装载成功 ...&);
catch (InterruptedException ex)
ex.printStackTrace();
// 实现 Image 里的 show() 方法
public void show()
System.out.println(&绘制实际的大图片&);
上面的程序代码暂停了 3s,这表明创建一个 BigImage 对象需要 3s 的时间开销——程序使用这种延迟来模拟装载此图片所导致的系统开销。如果不采用代理模式,当程序中创建 BigImage 时,系统将会产生 3s 的延迟。为了避免这种延迟,程序为 BigImage 对象提供一个代理对象,BigImage 类的代理类如下所示。
public class ImageProxy implements Image
// 组合一个 image 实例,作为被代理的对象
// 使用抽象实体来初始化代理对象
public ImageProxy(Image image)
this.image =
* 重写 Image 接口的 show() 方法
* 该方法用于控制对被代理对象的访问,
* 并根据需要负责创建和删除被代理对象
public void show()
// 只有当真正需要调用 image 的 show 方法时才创建被代理对象
if (image == null)
image = new BigImage();
image.show();
上面的 ImageProxy 代理类实现了与 BigImage 相同的 show() 方法,这使得客户端代码获取到该代理对象之后,可以将该代理对象当成 BigImage 来使用。
在 ImageProxy 类的 show() 方法中增加了控制逻辑,这段控制逻辑用于控制当系统真正调用 image 的 show() 时,才会真正创建被代理的 BigImage 对象。下面程序需要使用 BigImage 对象,但程序并不是直接返回 BigImage 实例,而是先返回 BigImage 的代理对象,如下面程序所示。
public class BigImageTest
public static void main(String[] args)
long start = System.currentTimeMillis();
// 程序返回一个 Image 对象,该对象只是 BigImage 的代理对象
Image image = new ImageProxy(null);
System.out.println(&系统得到 Image 对象的时间开销 :& +
(System.currentTimeMillis() - start));
// 只有当实际调用 image 代理的 show() 方法时,程序才会真正创建被代理对象。
image.show();
上面程序初始化 image 非常快,因为程序并未真正创建 BigImage 对象,只是得到了 ImageProxy 代理对象——直到程序调用 image.show() 方法时,程序需要真正调用 BigImage 对象的 show() 方法,程序此时才真正创建 BigImage 对象。运行上面程序,看到如图 6 所示的结果。
看到如图 6 所示的运行结果,读者应该能认同:使用代理模式提高了获取 Image 对象的系统性能。但可能有读者会提出疑问:程序调用 ImageProxy 对象的 show() 方法时一样需要创建 BigImage 对象啊,系统开销并未真正减少啊?只是这种系统开销延迟了而已啊?
我们可以从如下两个角度来回答这个问题:
把创建 BigImage 推迟到真正需要它时才创建,这样能保证前面程序运行的流畅性,而且能减少 BigImage 在内存中的存活时间,从宏观上节省了系统的内存开销。
有些情况下,也许程序永远不会真正调用 ImageProxy 对象的 show() 方法——意味着系统根本无须创建 BigImage 对象。在这种情形下,使用代理模式可以显著地提高系统运行性能。
与此完全类似的是,Hibernate 也是通过代理模式来“推迟”加载关联实体的时间,如果程序并不需要访问关联实体,那程序就不会去抓取关联实体了,这样既可以节省系统的内存开销,也可以缩短 Hibernate 加载实体的时间。
Hibernate 的延迟加载(lazy load)本质上就是代理模式的应用,我们在过去的岁月里就经常通过代理模式来降低系统的内存开销、提升应用的运行性能。Hibernate 充分利用了代理模式的这种优势,并结合了 Javassist 或 CGLIB 来动态地生成代理对象,这更加增加了代理模式的灵活性,Hibernate 给这种用法一个新名称:延迟加载。无论怎样,充分分析、了解这些开源框架的实现可以更好的感受经典设计模式的优势所在。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
(8)(1)(1)(1)(1)(1)(15)(8)(6)(1)(3)(1)(6)(3)(3)(10)优化Jquery,提升网页加载速度
字体:[ ] 类型:转载 时间:
本文是对优化Jquery,提升网页加载速度方面进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助
总是从ID选择器开始继承 在class前使用tag 将jquery对象缓存起来 掌握强大的链式操作 使用子查询 对直接的DOM操作进行限制 冒泡 消除无效查询 推迟到 $(window).load 压缩js 全面掌握jquery库
1. 总是从ID选择器开始继承
在jquery中最快的选择器是ID选择器. 因为它直接来自于Javascript的getElementById()方法. 代码如下:&div id="content"&&form method="post" action="/"&&h2&Traffic Light&/h2&&ul id="traffic_light"&&li&&input type="radio" class="on" name="light" value="red" /& Red&/li&&li&&input type="radio" class="off" name="light" value="yellow" /& Yellow&/li&&li&&input type="radio" class="off" name="light" value="green" /& Green&/li&&/ul&&input class="button" id="traffic_button" type="submit" value="Go" /&&/form&&/div& 像这样选择按钮是低效的:
var traffic_button = $('#content .button'); 用ID直接选择按钮效率更高:
var traffic_button = $('#traffic_button');
选择多个元素
提到多元素选择其实是在说DOM遍历和循环, 这些都是比较慢的东西.为了提高性能, 最好从就近的ID开始继承.
var traffic_lights = $('#traffic_light input');
2. 在class前使用tag
第二快的选择器是tag选择器($('head')). 同理,因为它来自原生的getElementsByTagName() 方法. 代码如下:&div id="content"&&form method="post" action="/"&&h2&Traffic Light&/h2&&ul id="traffic_light"&&li&&input type="radio" class="on" name="light" value="red" /& Red&/li&&li&&input type="radio" class="off" name="light" value="yellow" /& Yellow&/li&&li&&input type="radio" class="off" name="light" value="green" /& Green&/li&&/ul&&input class="button" id="traffic_button" type="submit" value="Go" /&&/form&&/div&总是用一个tag name来限制(修饰)class (并且不要忘记就近的ID):
var active_light = $('#traffic_light input.on');
注意: 在jquery中Class是最慢的选择器. IE浏览器下它会遍历所有DOM节点不管它用在那里.
不要用用tag name来修饰ID. 下面的例子将会遍历所有的div元素来查找id为'content'的哪一个节点:
var content = $('div#content'); 用ID修饰ID也是画蛇添足:
var traffic_light = $('#content #traffic_light');
3.将jquery对象缓存起来
要养成将jquery对象缓存进变量的习惯.
永远不要这样做: 代码如下:$('#traffic_light input.on).bind('click', function(){…});$('#traffic_light input.on).css('border', '3px dashed yellow');$('#traffic_light input.on).css('background-color', 'orange');$('#traffic_light input.on).fadeIn('slow'); 最好先将对象缓存进一个变量然后再操作: 代码如下:var $active_light = $('#traffic_light input.on');$active_light.bind('click', function(){…});$active_light.css('border', '3px dashed yellow');$active_light.css('background-color', 'orange');$active_light.fadeIn('slow'); 为了记住我们本地变量是jquery的封装, 通常用一个$作为变量前缀. 记住,永远不要让相同的选择器在你的代码里出现多次.
缓存jquery结果,备用 如果你打算将jquery结果对象用在程序的其它部分,或者你的function会多次执行, 那么就将他们缓存到一个全局变量中.
定义一个全局容器来存放jquery结果, 我们就可以在其它函数引用它们: 代码如下:// 在全局范围定义一个对象 (例如: window对象)window.$my ={// 初始化所有可能会不止一次要使用的查询head : $('head'),traffic_light : $('#traffic_light'),traffic_button : $('#traffic_button')};function do_something(){// 现在你可以引用存储的结果并操作它们var script = document.createElement('script');$my.head.append(script);// 当你在函数内部操作是, 可以继续将查询存入全局对象中去.$my.cool_results = $('#some_ul li');$my.other_results = $('#some_table td');// 将全局函数作为一个普通的jquery对象去使用.$my.other_results.css('border-color', 'red');$my.traffic_light.css('border-color', 'green');}4. 掌握强大的链式操作
上面的例子也可以写成这样: 代码如下:var $active_light = $('#traffic_light input.on');$active_light.bind('click', function(){…}).css('border', '3px dashed yellow').css('background-color', 'orange').fadeIn('slow'); 这样可以写更少的代码, 让我们的js更轻量.
5.使用子查询
jQuery 允许我们对一个已包装的对象使用附加的选择器操作. 因为我们已经在保存了一个父级对象在变量里, 这样大大提高对其子元素的操作: 代码如下:&div id="content"&&form method="post" action="/"&&h2&Traffic Light&/h2&&ul id="traffic_light"&&li&&input type="radio" class="on" name="light" value="red" /& Red&/li&&li&&input type="radio" class="off" name="light" value="yellow" /& Yellow&/li&&li&&input type="radio" class="off" name="light" value="green" /& Green&/li&&/ul&&input class="button" id="traffic_button" type="submit" value="Go" /&&/form&&/div&例如, 我们可以用子查询的方法来抓取到亮或不亮的灯, 并缓存起来以备后续操作. 代码如下:var $traffic_light = $('#traffic_light'),$active_light = $traffic_light.find('input.on'),$inactive_lights = $traffic_light.find('input.off'); 提示: 你可以用逗号分隔的方法一次声明多个局部变量–节省字节数
6.对直接的DOM操作进行限制
这里的基本思想是在内存中建立你确实想要的东西,然后更新DOM .这并不是一个jQuery最佳实践,但必须进行有效的JavaScript操作 .直接的DOM操作速度很慢.
例如,你想动态的创建一组列表元素, 千万不要这么做: 代码如下:var top_100_list = [...], // 假设这里是100个独一无二的字符串$mylist = $('#mylist'); // jQuery 选择到 &ul& 元素for (var i=0, l=top_100_list. i&l; i++){&&&&&& $mylist.append('&li&' + top_100_list[i] + '&/li&');}我们应该将整套元素字符串在插入进dom中之前全部创建好: 代码如下:var top_100_list = [...],$mylist = $('#mylist'),top_100_li = ""; // 这个变量将用来存储我们的列表元素for (var i=0, l=top_100_list. i&l; i++){&&&&&&& top_100_li += '&li&' + top_100_list[i] + '&/li&';}$mylist.html(top_100_li);我们在插入之前将多个元素包裹进一个单独的父级节点会更快: 代码如下:var top_100_list = [...],$mylist = $('#mylist'),top_100_ul = '&ul id="#mylist"&';for (var i=0, l=top_100_list. i&l; i++){&&&& top_100_ul += '&li&' + top_100_list[i] + '&/li&';}top_100_ul += '&/ul&'; //关闭无序列表$mylist.replaceWith(top_100_ul);如果你做了以上几条还是担心有性能问题,那么:
试试jquery的 clone() 方法, 它会创建一个节点树的副本, 它允许以"离线"的方式进行dom操作, 当你操作完成后再将其放回到节点树里.
使用 DOM DocumentFragments. 正如jQuery作者所言, 它的性能要明显优于直接的dom操作.
除非在特殊情况下, 否则每一个js事件(例如:click, mouseover, 等.)都会冒泡到父级节点. 当我们需要给多个元素调用同个函数时这点会很有用.
代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次, 并且可以计算出哪个节点触发了事件.
例如, 我们要为一个拥有很多输入框的表单绑定这样的行为: 当输入框被选中时为它添加一个class
像这样绑定事件是低效的: 代码如下:$('#entryform input).bind('focus', function(){$(this).addClass('selected');}).bind('blur', function(){$(this).removeClass('selected');}); 我们需要在父级监听获取焦点和失去焦点的事件: 代码如下:$('#entryform').bind('focus', function(e){&&&&&& var cell = $(e.target); // e.target grabs the node that triggered the event.&&&&&& cell.addClass('selected');}).bind('blur', function(e){&&&& var cell = $(e.target);&&& cell.removeClass('selected');});父级元素扮演了一个调度员的角色, 它可以基于目标元素绑定事件. 如果你发现你给很多元素绑定了同一个事件监听, 那么你肯定哪里做错了.
8.消除无效查询
尽管jquery可以很优雅的处理没有匹配元素的情况, 但它还是需要花费时间去寻找. 如果你整站只有一个全局js, 那么极有可能把所有的jquery函数塞进$(document)ready(function(){//所有你引以为傲的代码})里.
只运行在页面里用到的函数. 大多数有效的方法就是使用行内初始化函数, 这样你的模板就能准确的控制何时何处该执行js.
例如, 你的"文章"页面模板, 你可能会引用如下的代码在body结束处:
&script type="text/javascript&mylib.article.init();&/script&&/body&
如果你的页面模板包含一些多变的模块可能不会出现在页面中, 或者为了视觉呈现的原因你需要它们能够快速加载, 你可以将初始化函数紧跟在模块之后.
&ul id="traffic_light"&&li&&input type="radio" class="on" name="light" value="red" /& Red&/li&&li&&input type="radio" class="off" name="light" value="yellow" /& Yellow&/li&&li&&input type="radio" class="off" name="light" value="green" /& Green&/li&&/ul&&script type="text/javascript&mylib.traffic_light.init();&/script&
你的全局js库可能会是这样子的:
var mylib ={&&& article_page :&& {&&&&&&& init : function()&&&&& {&&&&&&&&&& // Article 特有的jQuery函数.&&&&& }&& },&& traffic_light :& {&&&&&& init : function()&&&&& {&&&&&&&&& // Traffic light 特有的jQuery函数.&&&&& }&& }}
9. 推迟到 $(window).load
jquery对于开发者来说有一个很诱人的东西, 可以把任何东西挂到$(document).ready下冒充事件. 在大多数例子中你都会发现这样的情况.
尽管$(document).rady 确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行. 如果你发现你的页面一直是载入中的状态, 很有可能就是$(document).ready函数引起的.
你可以通过将jquery函数绑定到$(window).load 事件的方法来减少页面载入时的cpu使用率. 它会在所有的html(包括&iframe&)被下载完成后执行.
$(window).load(function(){// 页面完全载入后才初始化的jQuery函数.});
多余的功能例如拖放, 视觉特效和动画, 预载入隐藏图像,等等. 都是适合这种技术的场合.
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 廷迟退体时间表 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信