Conditions | 4 |
Paths | 4 |
Total Lines | 263 |
Code Lines | 165 |
Lines | 0 |
Ratio | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 1 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | var original = require("original"); |
||
20 | function EventSource (url, eventSourceInitDict) { |
||
21 | var readyState = EventSource.CONNECTING; |
||
22 | Object.defineProperty(this, 'readyState', { |
||
23 | get: function () { |
||
24 | return readyState |
||
25 | } |
||
26 | }) |
||
27 | |||
28 | Object.defineProperty(this, 'url', { |
||
29 | get: function () { |
||
30 | return url |
||
31 | } |
||
32 | }) |
||
33 | |||
34 | var self = this; |
||
35 | self.reconnectInterval = 60000; |
||
36 | |||
37 | function onConnectionClosed () { |
||
38 | if (readyState === EventSource.CLOSED) return |
||
|
|||
39 | readyState = EventSource.CONNECTING |
||
40 | _emit('error', new Event('error')) |
||
41 | |||
42 | // The url may have been changed by a temporary |
||
43 | // redirect. If that's the case, revert it now. |
||
44 | if (reconnectUrl) { |
||
45 | url = reconnectUrl |
||
46 | reconnectUrl = null |
||
47 | } |
||
48 | setTimeout(function () { |
||
49 | if (readyState !== EventSource.CONNECTING) { |
||
50 | return; |
||
51 | } |
||
52 | connect(); |
||
53 | }, self.reconnectInterval) |
||
54 | } |
||
55 | |||
56 | var req; |
||
57 | var lastEventId = ""; |
||
58 | if (eventSourceInitDict && eventSourceInitDict.headers && eventSourceInitDict.headers["Last-Event-ID"]) { |
||
59 | lastEventId = eventSourceInitDict.headers["Last-Event-ID"] |
||
60 | delete eventSourceInitDict.headers["Last-Event-ID"] |
||
61 | } |
||
62 | |||
63 | var discardTrailingNewline = false; |
||
64 | var data = ''; |
||
65 | var eventName = ''; |
||
66 | |||
67 | var reconnectUrl = null; |
||
68 | |||
69 | function connect () { |
||
70 | var options = parse(url) |
||
71 | var isSecure = options.protocol === 'https:' |
||
72 | options.headers = { 'Cache-Control': 'no-cache', 'Accept': 'text/event-stream' } |
||
73 | if (lastEventId) options.headers['Last-Event-ID'] = lastEventId |
||
74 | if (eventSourceInitDict && eventSourceInitDict.headers) { |
||
75 | for (var i in eventSourceInitDict.headers) { |
||
76 | var header = eventSourceInitDict.headers[i] |
||
77 | if (header) { |
||
78 | options.headers[i] = header |
||
79 | } |
||
80 | } |
||
81 | } |
||
82 | |||
83 | // Legacy: this should be specified as `eventSourceInitDict.https.rejectUnauthorized`, |
||
84 | // but for now exists as a backwards-compatibility layer |
||
85 | options.rejectUnauthorized = !(eventSourceInitDict && !eventSourceInitDict.rejectUnauthorized) |
||
86 | |||
87 | // If specify http proxy, make the request to sent to the proxy server, |
||
88 | // and include the original url in path and Host headers |
||
89 | var useProxy = eventSourceInitDict && eventSourceInitDict.proxy |
||
90 | if (useProxy) { |
||
91 | var proxy = parse(eventSourceInitDict.proxy) |
||
92 | isSecure = proxy.protocol === 'https:' |
||
93 | |||
94 | options.protocol = isSecure ? 'https:' : 'http:'; |
||
95 | options.path = url; |
||
96 | options.headers.Host = options.host; |
||
97 | options.hostname = proxy.hostname; |
||
98 | options.host = proxy.host; |
||
99 | options.port = proxy.port; |
||
100 | } |
||
101 | |||
102 | // If https options are specified, merge them into the request options |
||
103 | if (eventSourceInitDict && eventSourceInitDict.https) { |
||
104 | for (var optName in eventSourceInitDict.https) { |
||
105 | if (httpsOptions.indexOf(optName) === -1) { |
||
106 | continue |
||
107 | } |
||
108 | |||
109 | var option = eventSourceInitDict.https[optName] |
||
110 | if (option !== undefined) { |
||
111 | options[optName] = option |
||
112 | } |
||
113 | } |
||
114 | } |
||
115 | |||
116 | // Pass this on to the XHR |
||
117 | if (eventSourceInitDict && eventSourceInitDict.withCredentials !== undefined) { |
||
118 | options.withCredentials = eventSourceInitDict.withCredentials |
||
119 | } |
||
120 | |||
121 | req = (isSecure ? https : http).request(options, function (res) { |
||
122 | // Handle HTTP errors |
||
123 | if (res.statusCode === 500 || res.statusCode === 502 || res.statusCode === 503 || res.statusCode === 504) { |
||
124 | _emit('error', new Event('error', {status: res.statusCode})) |
||
125 | onConnectionClosed() |
||
126 | return |
||
127 | } |
||
128 | |||
129 | // Handle HTTP redirects |
||
130 | if (res.statusCode === 301 || res.statusCode === 307) { |
||
131 | if (!res.headers.location) { |
||
132 | // Server sent redirect response without Location header. |
||
133 | _emit('error', new Event('error', {status: res.statusCode})) |
||
134 | return |
||
135 | } |
||
136 | if (res.statusCode === 307) reconnectUrl = url |
||
137 | url = res.headers.location |
||
138 | process.nextTick(connect) |
||
139 | return |
||
140 | } |
||
141 | |||
142 | if (res.statusCode !== 200) { |
||
143 | _emit('error', new Event('error', {status: res.statusCode})) |
||
144 | return self.close() |
||
145 | } |
||
146 | |||
147 | // protect against multiple connects |
||
148 | //https://github.com/tigertext/eventsource/commit/ca8a6e0ca0db10c23ba7bf2b7f8affaa23d7a265 |
||
149 | if (readyState === EventSource.OPEN) { |
||
150 | return; |
||
151 | } |
||
152 | |||
153 | readyState = EventSource.OPEN |
||
154 | res.on('close', function () { |
||
155 | res.removeAllListeners('close') |
||
156 | res.removeAllListeners('end') |
||
157 | onConnectionClosed() |
||
158 | }) |
||
159 | |||
160 | res.on('end', function () { |
||
161 | res.removeAllListeners('close') |
||
162 | res.removeAllListeners('end') |
||
163 | onConnectionClosed() |
||
164 | }) |
||
165 | _emit('open', new Event('open')) |
||
166 | |||
167 | // text/event-stream parser adapted from webkit's |
||
168 | // Source/WebCore/page/EventSource.cpp |
||
169 | var buf = '' |
||
170 | res.on('data', function (chunk) { |
||
171 | buf += chunk |
||
172 | |||
173 | var pos = 0 |
||
174 | var length = buf.length |
||
175 | |||
176 | while (pos < length) { |
||
177 | if (discardTrailingNewline) { |
||
178 | if (buf[pos] === '\n') { |
||
179 | ++pos |
||
180 | } |
||
181 | discardTrailingNewline = false |
||
182 | } |
||
183 | |||
184 | var lineLength = -1 |
||
185 | var fieldLength = -1 |
||
186 | var c |
||
187 | |||
188 | for (var i = pos; lineLength < 0 && i < length; ++i) { |
||
189 | c = buf[i] |
||
190 | if (c === ':') { |
||
191 | if (fieldLength < 0) { |
||
192 | fieldLength = i - pos |
||
193 | } |
||
194 | } else if (c === '\r') { |
||
195 | discardTrailingNewline = true |
||
196 | lineLength = i - pos |
||
197 | } else if (c === '\n') { |
||
198 | lineLength = i - pos |
||
199 | } |
||
200 | } |
||
201 | |||
202 | if (lineLength < 0) { |
||
203 | break |
||
204 | } |
||
205 | |||
206 | parseEventStreamLine(buf, pos, fieldLength, lineLength) |
||
207 | |||
208 | pos += lineLength + 1 |
||
209 | } |
||
210 | |||
211 | if (pos === length) { |
||
212 | buf = '' |
||
213 | } else if (pos > 0) { |
||
214 | buf = buf.slice(pos) |
||
215 | } |
||
216 | }) |
||
217 | }) |
||
218 | |||
219 | req.on('error', onConnectionClosed) |
||
220 | if (req.setNoDelay) req.setNoDelay(true) |
||
221 | req.end() |
||
222 | } |
||
223 | |||
224 | connect() |
||
225 | |||
226 | function _emit () { |
||
227 | if (self.listeners(arguments[0]).length > 0) { |
||
228 | self.emit.apply(self, arguments) |
||
229 | } |
||
230 | } |
||
231 | |||
232 | this._close = function () { |
||
233 | if (readyState === EventSource.CLOSED) return |
||
234 | readyState = EventSource.CLOSED |
||
235 | if (req.abort) req.abort() |
||
236 | if (req.xhr && req.xhr.abort) req.xhr.abort() |
||
237 | } |
||
238 | |||
239 | function parseEventStreamLine (buf, pos, fieldLength, lineLength) { |
||
240 | if (lineLength === 0) { |
||
241 | if (data.length > 0) { |
||
242 | var type = eventName || 'message' |
||
243 | _emit(type, new MessageEvent(type, { |
||
244 | data: data.slice(0, -1), // remove trailing newline |
||
245 | lastEventId: lastEventId, |
||
246 | origin: original(url) |
||
247 | })) |
||
248 | data = '' |
||
249 | } |
||
250 | eventName = void 0 |
||
251 | } else if (fieldLength > 0) { |
||
252 | var noValue = fieldLength < 0 |
||
253 | var step = 0 |
||
254 | var field = buf.slice(pos, pos + (noValue ? lineLength : fieldLength)) |
||
255 | |||
256 | if (noValue) { |
||
257 | step = lineLength |
||
258 | } else if (buf[pos + fieldLength + 1] !== ' ') { |
||
259 | step = fieldLength + 1 |
||
260 | } else { |
||
261 | step = fieldLength + 2 |
||
262 | } |
||
263 | pos += step |
||
264 | |||
265 | var valueLength = lineLength - step |
||
266 | var value = buf.slice(pos, pos + valueLength) |
||
267 | |||
268 | if (field === 'data') { |
||
269 | data += value + '\n' |
||
270 | } else if (field === 'event') { |
||
271 | eventName = value |
||
272 | } else if (field === 'id') { |
||
273 | lastEventId = value |
||
274 | } else if (field === 'retry') { |
||
275 | var retry = parseInt(value, 10) |
||
276 | if (!Number.isNaN(retry)) { |
||
277 | self.reconnectInterval = retry |
||
278 | } |
||
279 | } |
||
280 | } |
||
281 | } |
||
282 | } |
||
283 | |||
401 |
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.