@@ -661,25 +661,23 @@ JavaScript没有类,所以一字一句地说单例的定义并没有什么意
661661
662662外观模式在做一些重新设计和重构工作时也很有用。当你想用一个不同的实现来替换某个对象的时候,你可能需要花相当长一段时间才能完成(一个复杂的对象),与此同时,一些使用这个新对象的代码也在被同步编写。你可以先想好新对象的API,然后在旧的对象前面使用新的API创建一个外观方法。使用这种方式,当你完全替换掉旧的对象的时候,你只需要修改少量的调用代码,因为新的代码已经是在使用新的API了。
663663
664- <a name =" a16 " ></a >
665664## 代理模式
666665
667- 在代理设计模式中 ,一个对象充当了另一个对象的接口的角色。它和外观模式不一样,外观模式带来的方便仅限于将几个方法调用联合起来。而代理对象位于某个对象和它的客户之间 ,可以保护对对象的访问。
666+ 在代理模式中 ,一个对象充当了另一个对象的接口的角色。它和外观模式不一样,外观模式带来的方便仅限于将几个方法调用联合起来。而代理对象位于某个对象和它的使用者之间 ,可以保护对对象的访问。
668667
669- 这个模式看起来开销有点大,但在出于性能考虑时非常有用。代理对象可以作为对象(也叫“真正的主体”)的保护者,让真正的主体对象做尽量少的工作 。
668+ 这个模式看起来开销有点大,但在出于性能考虑时非常有用。代理对象可以作为目标对象的保护者,让目标对象做尽量少的工作 。
670669
671- 一种示例用法是我们称之为 “懒初始化”(延迟初始化)的东西。假设初始化真正的主体是开销很大的,并且正好客户代码将它初始化后并不真正使用它 。在这种情况下,代理对象可以作为真正的主体的接口起到帮助作用 。代理对象接收到初始化请求,但在真正的主体真正被使用之前都不会将它传递过去 。
670+ 一种示例用法是 “懒初始化”(延迟初始化)。假设负责初始化的对象是开销很大的,并且正好使用者将它初始化后并不真正使用它 。在这种情况下,代理对象可以作为目标对象的接口起到帮助作用 。代理对象接收到初始化请求,但在目标对象真正被使用之前都不会将请求传递过去 。
672671
673- 图7-2展示了这个场景,当客户代码发出初始化请求时 ,代理对象回复一切就绪,但并没有将请求传递过去,只有在客户代码真正需要真正的主体做些工作的时候才将两个请求一起传递过去 。
672+ 图7-2展示了这个场景,当使用目标对象的代码发出初始化请求时 ,代理对象回复一切就绪,但并没有将请求传递过去,只有在真正需要目标对象做些工作的时候才将两个请求一起传递过去 。
674673
675- ![ 图7-2 通过代理对象时客户代码与真正的主体的关系 ] ( ./Figure/chapter7/7-2.jpg )
674+ ![ 图7-2 通过代理对象时目标对象与使用者的关系 ] ( ./Figure/chapter7/7-2.jpg )
676675
677- 图7-2 通过代理对象时客户代码与真正的主体的关系
676+ 图7-2 通过代理对象时目标对象与使用者的关系
678677
679- <a name =" a17 " ></a >
680678### 一个例子
681679
682- 在真正的主体做某件工作开销很大时 ,代理模式很有用处。在web应用中,开销最大的操作之一就是网络请求,此时尽可能地合并HTTP请求是有意义的。我们来看一个这种场景下应用代理模式的实例。
680+ 在目标对象做某件工作开销很大时 ,代理模式很有用处。在web应用中,开销最大的操作之一就是网络请求,此时尽可能地合并HTTP请求是有意义的。我们来看一个这种场景下应用代理模式的实例。
683681
684682#### 一个视频列表(expando)
685683
@@ -697,14 +695,14 @@ JavaScript没有类,所以一字一句地说单例的定义并没有什么意
697695
698696这个应用中最主要的角色是两个对象:
699697
700- - videos
698+ - ` videos `
701699
702- 负责对信息区域展开/收起(videos.getInfo()方法)和播放视频的响应(videos.getPlayer()方法)
703- - http
700+ 负责对信息区域展开/收起(` videos.getInfo()` 方法)和播放视频的响应(` videos.getPlayer()` 方法)
701+ - ` http `
704702
705- 负责通过http .makeRequest()方法与服务端通讯
703+ 负责通过`http .makeRequest()` 方法与服务端通讯
706704
707- 当没有代理对象的时候,videos.getInfo()会为每个视频调用一次http .makeRequest()方法。当我们添加代理对象proxy后,它将位于vidoes和http中间,接手对makeRequest() 的调用,并在可能的时候合并请求。
705+ 当没有代理对象的时候,` videos.getInfo() ` 会为每个视频调用一次 ` http .makeRequest()` 方法。当我们添加代理对象 ` proxy ` 后,它将位于 ` vidoes ` 和 ` http ` 中间,接手对 ` makeRequest() ` 的调用,并在可能的时候合并请求。
708706
709707我们首先看一下没有代理对象的代码,然后添加代理对象来提升应用的响应速度。
710708
@@ -730,13 +728,13 @@ HTML代码仅仅是一个链接列表:
730728
731729#### 事件处理
732730
733- 现在我们来看一下事件处理的逻辑。首先我们定义一个方便的快捷函数$ :
731+ 现在我们来看一下事件处理的逻辑。首先我们定义一个方便的快捷函数` $ ` :
734732
735733 var $ = function (id) {
736734 return document.getElementById(id);
737735 };
738736
739- 使用事件代理(第8章有更多关于这个模式的内容),我们将所有id ="vids"的条目上的点击事件统一放到一个函数中处理:
737+ 使用事件代理(第八章有更多关于这个模式的内容),我们将所有 ` id ="vids"` 的条目上的点击事件统一放到一个函数中处理:
740738
741739 $('vids').onclick = function (e) {
742740 var src, id;
@@ -764,19 +762,19 @@ HTML代码仅仅是一个链接列表:
764762 videos.getInfo(id);
765763 };
766764
767- #### videos对象
765+ #### ` videos ` 对象
768766
769- videos对象有三个方法 :
767+ ` videos ` 对象有三个方法 :
770768
771- - getPlayer()
769+ - ` getPlayer() `
772770
773771 返回播放视频需要的HTML代码(跟我们讨论的无关)
774- - updateList()
772+ - ` updateList() `
775773
776- 网络请求的回调函数,接受从服务器返回的数据,然后生成用于视频详细信息的HTML代码。这一部分也没有什么太有趣的事情 。
777- - getInfo()
774+ 网络请求的回调函数,接受从服务器返回的数据,然后生成用于视频详细信息的HTML代码。这一部分也没有什么需要关注的事情 。
775+ - ` getInfo() `
778776
779- 这个方法切换视频信息的可视状态,同时也调用http对象的方法,并传递updaetList() 作为回调函数。
777+ 这个方法切换视频信息的可视状态,同时也调用`http`对象的方法,并传递`updaetList()` 作为回调函数。
780778
781779下面是这个对象的代码片段:
782780
@@ -803,9 +801,9 @@ videos对象有三个方法:
803801 }
804802 };
805803
806- #### http对象
804+ #### ` http ` 对象
807805
808- http对象只有一个方法 ,它向Yahoo!的YQL服务发起一个JSONP请求:
806+ ` http ` 对象只有一个方法 ,它向Yahoo!的YQL服务发起一个JSONP请求:
809807
810808 var http = {
811809 makeRequest: function (ids, callback) {
@@ -829,23 +827,23 @@ http对象只有一个方法,它向Yahoo!的YQL服务发起一个JSONP请求
829827
830828当所有的六个视频都被选中后,将会向服务端发起六个独立的像这样的YQL请求:
831829
832- select * from music.video.id where ids IN ("2158073")
830+ select * from music.video.id where ids IN ("2158073")
833831
834832#### 代理对象
835833
836- 前面的代码工作得很正常 ,但我们可以让它工作得更好。proxy对象就在这样的场景中出现,并接管了http和videos对象之间的通讯 。它将使用一个简单的逻辑来尝试合并请求:50ms的延迟。videos对象并不直接调用后台接口,而是调用proxy对象的方法。proxy对象在转发这个请求前将会等待一段时间,如果在等待的50ms内有另一个来自videos的调用 ,则它们将被合并为同一个请求。50ms的延迟对用户来说几乎是无感知的,但是却可以用来合并请求以提升点击“toggle”时的体验,一次展开多个视频。它也可以显著降低服务器的负载,因为web服务器只需要处理更少量的请求。
834+ 前面的代码工作得很好 ,但我们可以让它工作得更好。` proxy ` 对象就在这样的场景中出现,并接管了 ` http ` 和 ` videos ` 对象之间的通讯 。它将使用一个简单的逻辑来尝试合并请求:50ms的延迟。` videos ` 对象并不直接调用后台接口,而是调用 ` proxy ` 对象的方法。 ` proxy ` 对象在转发这个请求前将会等待一段时间,如果在等待的50ms内有另一个来自 ` videos ` 的调用 ,则它们将被合并为同一个请求。50ms的延迟对用户来说几乎是无感知的,但是却可以用来合并请求以提升点击“toggle”时的体验,一次展开多个视频。它也可以显著降低服务器的负载,因为web服务器只需要处理更少量的请求。
837835
838836合并后查询两个视频信息的YQL大概是这样:
839837
840838 select * from music.video.id where ids IN ("2158073", "123456")
841839
842- 在修改后的代码中,唯一的变化是videos .getInfo()现在调用的是proxy .makeRequest()而不是http .makeRequest(),像这样:
840+ 在修改后的代码中,唯一的变化是 ` videos .getInfo()` 现在调用的是 ` proxy .makeRequest()` 而不是 ` http .makeRequest()` ,像这样:
843841
844842 proxy.makeRequest(id, videos.updateList, videos);
845843
846- proxy对象创建了一个队列来收集50ms之内接受到的视频ID,然后将这个队列传递给http对象 ,并提供回调函数,因为videos .updateList()只能处理一次接收到的数据。(译注:指每次传入的回调函数只能处理当次接收到的数据。)
844+ ` proxy ` 对象创建了一个队列来收集50ms之内接受到的视频ID,然后将这个队列传递给 ` http ` 对象 ,并提供回调函数,因为 ` videos .updateList()` 只能处理一个接收到的视频信息。
847845
848- 下面是proxy对象的代码 :
846+ 下面是 ` proxy ` 对象的代码 :
849847
850848 var proxy = {
851849 ids: [],
@@ -854,13 +852,13 @@ proxy对象创建了一个队列来收集50ms之内接受到的视频ID,然后
854852 callback: null,
855853 context: null,
856854 makeRequest: function (id, callback, context) {
857- // add to the queue
855+ // 添加到队列
858856 this.ids.push(id);
859857
860858 this.callback = callback;
861859 this.context = context;
862860
863- // set up timeout
861+ // 设置延时
864862 if (!this.timeout) {
865863 this.timeout = setTimeout(function () {
866864 proxy.flush();
@@ -871,28 +869,28 @@ proxy对象创建了一个队列来收集50ms之内接受到的视频ID,然后
871869
872870 http.makeRequest(this.ids, "proxy.handler");
873871
874- // clear timeout and queue
872+ // 清除延时和队列
875873 this.timeout = null;
876874 this.ids = [];
877875
878876 },
879877 handler: function (data) {
880878 var i, max;
881879
882- // single video
880+ // 单个视频
883881 if (parseInt(data.query.count, 10) === 1) {
884882 proxy.callback.call(proxy.context, data.query.results.Video);
885883 return;
886884 }
887885
888- // multiple videos
886+ // 多个视频
889887 for (i = 0, max = data.query.results.Video.length; i < max; i += 1) {
890888 proxy.callback.call(proxy.context, data.query.results.Video[i]);
891889 }
892890 }
893891 };
894892
895- 了解代理模式后就在只简单地改动一下原来的代码的情况下 ,将多个web service请求合并为一个。
893+ 使用代理模式可以在只改动一处原来代码的情况下 ,将多个web service请求合并为一个。
896894
897895图7-4和7-5展示了使用代理模式将与服务器三次数据交互(不用代理模式时)变为一次交互的过程。
898896
@@ -905,9 +903,9 @@ proxy对象创建了一个队列来收集50ms之内接受到的视频ID,然后
905903图7-5 通过一个代理对象合并请求,减少与服务器数据交互
906904
907905
908- #### 使用代理对象做缓存
906+ ### 使用代理对象做缓存
909907
910- 在这个例子中,客户对象( videos)已经可以做到不对同一个对象重复发出请求。 但现实情况中并不总是这样。这个代理对象还可以通过缓存之前的请求结果到cache属性中来进一步保护真正的主体http对象 (图7-6)。然后当videos对象需要对同一个ID的视频请求第二次时,proxy对象可以直接从缓存中取出 ,从而避免一次网络交互。
908+ 在这个例子中,目标对象的使用者( ` videos ` )已经可以做到不对同一个对象重复发出请求, 但现实情况中并不总是这样。其实这个代理对象还可以通过缓存之前的请求结果到 ` cache ` 属性中来进一步保护 ` http ` 对象 (图7-6)。然后当 ` videos ` 对象需要对同一个ID的视频请求第二次时, ` proxy ` 对象可以直接从缓存中取出 ,从而避免一次网络交互。
911909
912910![ 图7-6 代理缓存] ( ./Figure/chapter7/7-6.jpg )
913911
0 commit comments