Skip to content

Commit c18c2cd

Browse files
committed
代理模式 校对完毕
1 parent 674fd69 commit c18c2cd

File tree

1 file changed

+36
-38
lines changed

1 file changed

+36
-38
lines changed

chapter7.markdown

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)