【オリジナル】backbone 1.1.0ソース解析のEvents
38655 ワード
最近nodeのソースコードを見ていますが、backboneの応用はまだ広いです.でも、前の勉強はすっかり忘れてしまいました.その時はメモをしていなかったことを後悔しています.
だから、いかんせん使いたいのはもっと良くて、ソースコードをはっきり見なければなりません.だからやはりソースコードの注釈ノートを残して、自分のために忘れようとします.
まず、ここではBackbone.Eventsの実装コードの注釈です.これはバックエンドのnodejs部分であれ、イベントベースのメカニズムの一つです.
すべてとても広い作用を持っています.さらにnodejsの非同期のメカニズムはもっと必要です.いくつかのロジックの問題を処理します.(もちろんプロモーションはあなたのようなpbsubよりも非同期に適しています.ハ、私はただ事件のメカニズムを示すようなものです.
重要性ですね
以下はコードに対するコメントです.間違いがあれば指摘してください.
だから、いかんせん使いたいのはもっと良くて、ソースコードをはっきり見なければなりません.だからやはりソースコードの注釈ノートを残して、自分のために忘れようとします.
まず、ここではBackbone.Eventsの実装コードの注釈です.これはバックエンドのnodejs部分であれ、イベントベースのメカニズムの一つです.
すべてとても広い作用を持っています.さらにnodejsの非同期のメカニズムはもっと必要です.いくつかのロジックの問題を処理します.(もちろんプロモーションはあなたのようなpbsubよりも非同期に適しています.ハ、私はただ事件のメカニズムを示すようなものです.
重要性ですね
以下はコードに対するコメントです.間違いがあれば指摘してください.
1 // Backbone.Events
2 // ---------------
3
4 // A module that can be mixed in to *any object* in order to provide it with
5 // custom events. You may bind with `on` or remove with `off` callback
6 // functions to an event; `trigger`-ing an event fires all callbacks in
7 // succession.
8 //
9 // var object = {};
10 // _.extend(object, Backbone.Events);
11 // object.on('expand', function(){ alert('expanded'); });
12 // object.trigger('expand');
13 //
14 var Events = Backbone.Events = {
15
16 // Bind an event to a `callback` function. Passing `"all"` will bind
17 // the callback to all events fired.
18 on: function(name, callback, context) {
19 // :
20 // 1. , eventsApi , eventsApi false, return
21 // 2. , , return
22 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
23 // , name ( :click | custom)
24 // ,
25 this._events || (this._events = {});
26 var events = this._events[name] || (this._events[name] = []);
27
28 // events
29 // _events : {
30 // click : [{
31 // callback : cb1,
32 // context : ctx1,
33 // ctx : ctx1 || this
34 // },{
35 // callback : cb2,
36 // context : ctx2,
37 // ctx : ctx2 || this
38 // }, ...],
39 // blur : [{...}, {...}, ...],
40 // ...
41 // }
42 events.push({callback: callback, context: context, ctx: context || this});
43 return this;
44 },
45
46 // Bind an event to only be triggered a single time. After the first time
47 // the callback is invoked, it will be removed.
48 once: function(name, callback, context) {
49 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
50 var self = this;
51 // callback , newCallback calllback,
52 // ,newCallback callback , callback
53 // once , callback
54 var once = _.once(function() {
55 self.off(name, once);
56 callback.apply(this, arguments);
57 });
58 // callback, off
59 once._callback = callback;
60 // .on()
61 return this.on(name, once, context);
62 },
63
64 // Remove one or many callbacks. If `context` is null, removes all
65 // callbacks with that function. If `callback` is null, removes all
66 // callbacks for the event. If `name` is null, removes all bound
67 // callbacks for all events.
68 off: function(name, callback, context) {
69 var retain, ev, events, names, i, l, j, k;
70 // :
71 // 1. , , return
72 // 2.
73 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
74 // obj.off() , obj
75 // _events
76 if (!name && !callback && !context) {
77 this._events = {};
78 return this;
79 }
80
81 // name , obj.off(undefined, cb1, ctx1)
82 // name ( _.keys(this._events))
83 names = name ? [name] : _.keys(this._events);
84
85 // name events
86 for (i = 0, l = names.length; i < l; i++) {
87 name = names[i];
88 if (events = this._events[name]) {
89 this._events[name] = retain = [];
90
91 // callback context
92 // off
93 // _events, _events
94 if (callback || context) {
95 for (j = 0, k = events.length; j < k; j++) {
96 ev = events[j];
97 // callback context ,
98 // _callback .once callback , evn.callback , callback _callback
99 if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
100 (context && context !== ev.context)) {
101 retain.push(ev);
102 }
103 }
104 }
105 // , , _events key
106 if (!retain.length) delete this._events[name];
107 }
108 }
109
110 return this;
111 },
112
113 // Trigger one or many events, firing all bound callbacks. Callbacks are
114 // passed the same arguments as `trigger` is, apart from the event name
115 // (unless you're listening on `"all"`, which will cause your callback to
116 // receive the true name of the event as the first argument).
117 trigger: function(name) {
118 if (!this._events) return this;
119 // callback
120 var args = slice.call(arguments, 1);
121 // trigger
122 if (!eventsApi(this, 'trigger', name, args)) return this;
123 //
124 var events = this._events[name];
125 // all (all ,all )
126 var allEvents = this._events.all;
127 // all
128 // ,all all
129 if (events) triggerEvents(events, args);
130 if (allEvents) triggerEvents(allEvents, arguments);
131 return this;
132 },
133
134 // Tell this object to stop listening to either specific events ... or
135 // to every object it's currently listening to.
136 stopListening: function(obj, name, callback) {
137 var listeningTo = this._listeningTo;
138 if (!listeningTo) return this;
139 //
140 var remove = !name && !callback;
141 // (obj, {click: cb1, change: cb2})
142 // context , this
143 if (!callback && typeof name === 'object') callback = this;
144 // obj, obj
145 // ,
146 if (obj) (listeningTo = {})[obj._listenId] = obj;
147 for (var id in listeningTo) {
148 obj = listeningTo[id];
149 obj.off(name, callback, this);
150 //
151 // 1. obj ( name callback )
152 // 2. obj , ?
153 if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
154 }
155 return this;
156 }
157
158 };
159
160 // Regular expression used to split event strings.
161 var eventSplitter = /\s+/;
162
163 // Implement fancy features of the Events API such as multiple event
164 // names `"change blur"` and jQuery-style event maps `{change: action}`
165 // in terms of the existing API.
166 // ({}, 'on', 'click blur', [function () {}, undefined])
167 var eventsApi = function(obj, action, name, rest) {
168 if (!name) return true;
169
170 // Handle event maps.
171 //
172 // :(obj, 'on', {'click': function x () {}, 'blur': function xx () {}}, context)
173 if (typeof name === 'object') {
174 for (var key in name) {
175 // action(on | off | once), , 。
176 obj[action].apply(obj, [key, name[key]].concat(rest));
177 }
178 return false;
179 }
180
181 // Handle space separated event names.
182 // ( )
183 // :(obj, 'on', 'click blur', function () {}, context)
184 if (eventSplitter.test(name)) {
185 var names = name.split(eventSplitter);
186 for (var i = 0, l = names.length; i < l; i++) {
187 obj[action].apply(obj, [names[i]].concat(rest));
188 }
189 return false;
190 }
191
192 return true;
193 };
194
195 // A difficult-to-believe, but optimized internal dispatch function for
196 // triggering events. Tries to keep the usual cases speedy (most internal
197 // Backbone events have 3 arguments).
198 // , arg 3 , call ,
199 // call apply (http://jsperf.com/function-versus-function-call-versus-function-apply)
200 var triggerEvents = function(events, args) {
201 var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
202 switch (args.length) {
203 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
204 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
205 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
206 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
207 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
208 }
209 };
210
211 var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
212
213 // Inversion-of-control versions of `on` and `once`. Tell *this* object to
214 // listen to an event in another object ... keeping track of what it's
215 // listening to.
216 // listenTo listernToOnce
217 // :
218 // 1. obj _listenId id
219 // 2. ( ) map listeningTo , id obj
220 // 3. obj this
221 // obj on once ,
222 // , , 1,2
223
224 _.each(listenMethods, function(implementation, method) {
225 Events[method] = function(obj, name, callback) {
226 var listeningTo = this._listeningTo || (this._listeningTo = {});
227 var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
228 listeningTo[id] = obj;
229 // (obj, {click: cb1, change: cb2})
230 // context , this
231 if (!callback && typeof name === 'object') callback = this;
232 obj[implementation](name, callback, this);
233 return this;
234 };
235 });
236
237 // Aliases for backwards compatibility.
238 //
239 Events.bind = Events.on;
240 Events.unbind = Events.off;
241
242 // Allow the `Backbone` object to serve as a global event bus, for folks who
243 // want global "pubsub" in a convenient place.
244 // Backbone
245 _.extend(Backbone, Events);
おやすみなさい