作者PsMonkey (痞子军团团长)
看板Translate-CS
标题[翻译] GWT RPC 的 deserialize 行为与 IE8
时间Tue Apr 1 16:41:07 2014
原文网址:
http://blog.oio.de/2014/03/28/gwt-rpc-deserialization-vs-ie8/
译文网址:
http://blog.dontcareabout.us/2014/04/gwt-rpc-deserialize-ie8.html
BBS 版以 markdown 语法撰写
______________________________________________________________________
几乎每个 web 开发人员都知道,
当 JS 执行时间过久 browser 就会跳出讨厌的对话框问你要不要取消。
在 [IE 上头]会显示「这个网页的指令码造成 Internet Explorer 执行速度缓慢」。
这篇文章将说明 IE8 的特殊行为、
它如何影响 GWT RPC 的 deserialize 机制、
以及如何解决这些问题。
IE8 上的缓慢 JS
---------------
大多数 browser 在等待一段特定时间後(例如 5 秒),
会显示前面提到的讯息。
这在 IE8 上有些不同,它判断的依据是「执行 script 叙述的数量」,
预设是 500 万个叙述。
这烂爆了,因为 2014 年典型的桌机执行起来不到 1 秒,
於是这就变成一个困扰。
所以,比起其他 browser,IE8 更难避免跳出那个讯息。
GWT RPC 与缓慢的执行速度
------------------------
在 GWT 中,我们有工具来避免这类问题。
关键是 [Scheduler class],
这能够让我们在一个新的 JS 区段(`scheduleDeferred`)执行程式码,
所以计数器会重置。
即使 incremental execution 也是可以用 `Scheduler`。
有某些情况下是没办法单纯把一些程式码延迟执行来避免这些问题。
其中一种状况是 GWT RPC 的 deserialize 行为。
下列的特性会增加 deserialize 行为的程式数量:
* RPC 所要掌控的 class 数量
* data model 的复杂度
* 在一次 RPC 呼叫中传输的 data / object 数量
这里有一些通用的建议可以协助优化 GWT RPC serialize 机制的效能:
* 尽可能使用最具体的 interface / class
* 不要在 GWT RPC 的参数、回传值、或是内含的 field,用 `Serializable`。
* 另一个例子是:要用 `ArrayList` 而不是用 `List`
* 只传输你真正需要的资料(包含仔入其他资料所需的 ID)
有趣的组合:Java Collection + GWT RPC
-------------------------------------
有一类问题是 Java Collection API 所导致的。
我最近遇到 JS 在 deserialize 时执行缓慢的问题,
传输的资料量小於 100KB。
这是重度使用 `HashSet` 跟 `HashMap` 所造成的。
在 deserialize 时会造成几百万行的 JS 叙述。
让我们看看一个 Map 在 deserialize 时会发生什麽事:
public static void deserialize(
SerializationStreamReader streamReader, Map instance)
throws SerializationException
{
int size = streamReader.readInt();
for (int i = 0; i < size; ++i) {
Object key = streamReader.readObject();
Object value = streamReader.readObject();
instance.put(key, value);
}
}
这段程式码用了正规的 `put()` 来增加所有的转换值。
对 `HashMap` 而言会造成额外的 JS 叙述:
* 作为 key 值的 object 会呼叫很多次 `hashCode()` / `equals()`
* 找到正确的地方来插入 entry 的代价是很昂贵的
你把越多 entry 加到 `Map` 中,要付出的代价就越高。
这件事对 `HashSet` 也适用,因为它们使用相同的机制。
实际上,这些 `Map` 跟 `Set` 是用来优化存取多个 object 的状况。
解决方法是用 `List`(就 deserialize 而言比较「便宜」)来传输资料,
然後到了 client 再对应到最佳化的资料结构。
用 transient field 是一个好用的技巧,
它会在传输 object 的时候隐藏起来不被处理:
private List<MyType> data;
private transient Map<MyKey, MyValue> optimizedData;
public Map<MyKey, MyValue> getOptimizedData() {
if(optimizedData == null) {
optimizedData = optimizeIt();
}
return optimizedData;
}
如此会让 `optimizedData` 这个 field 不会被 serialize。
在第一次存取资料时会作初始化的动作,然後 cache 起来留给後头使用。
[IE 上头]:
http://support.microsoft.com/kb/175500
[Scheduler class]:
http://www.gwtproject.org/javadoc/latest/com/google/gwt/core/client/Scheduler.html
--
钱锺书:
说出来的话
http://www.psmonkey.org
比不上不说出来的话
Java 版 cookcomic 版
只影射着说不出来的话
and more......
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 59.115.237.42
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/Translate-CS/M.1396341671.A.B39.html