├── LICENSE
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 IDSFN
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Write JS code that performs better!
4 | __Author: Nedal Kouissi__
5 |
6 | >Simple tips and healthy habits you can follow to be capable of drastically reducing the browser's workload and time needed to render each frame.
7 |
8 |
9 | ### In this article
10 | + [Caching your scripts](#id-section1)
11 | + [Compressing your scripts](#id-section2)
12 | + [Declare variables when needed](#id-section3)
13 | + [Create variable references](#id-section4)
14 | + [Condense variables using definition](#id-section5)
15 | + [Always use ===](#id-section6)
16 | + [Avoid Eval](#id-section7)
17 | + [Watch yourself when you're on closures](#id-section8)
18 | + [Prototype for static methods](#id-section9)
19 | + [Allocate only what you need](#id-section10)
20 | + [Be aware of any event, interval you add](#id-section11)
21 | + [Reduce reflow and repaint on your page](#id-section12)
22 | + [async & deffer](#id-section13)
23 | + [to be continue](#id-section14)
24 |
25 |
26 |
27 |
28 | ## Cahing your scripts:
29 |
30 | First always use CDN whenever it's available, it helps to avoid overloading and crashing of your website.
31 |
32 | The below method is called __"Expires"__ and it works just fine for most people using __.htaccess__, so it takes care of caching for most people who are just getting started. If for some reasons expiry rules didn't work for your server then you can try to use __"Cache Control"__.
33 |
34 | ```
35 | ## TURN ETag CACHING OFF ##
36 |
37 | Header unset Etag
38 | FileETag none
39 |
40 |
41 | ## EXPIRES CACHING ##
42 |
43 | ExpiresActive On
44 | ExpiresByType image/jpg "access 1 year"
45 | ExpiresByType image/jpeg "access 1 year"
46 | ExpiresByType image/gif "access 1 year"
47 | ExpiresByType image/png "access 1 year"
48 | ExpiresByType text/css "access 1 month"
49 | ExpiresByType text/html "access 1 week"
50 | ExpiresByType application/pdf "access 1 month"
51 | ExpiresByType text/x-javascript "access 1 month"
52 | ExpiresByType application/x-shockwave-flash "access 1 month"
53 | ExpiresByType image/x-icon "access 1 year"
54 | ExpiresDefault "access 1 month"
55 |
56 | ```
57 | After updating your .htaccess file refresh your website (more than once), then open the network tab
58 |
59 | 
60 |
61 | Select a js file for example and check if the difference between __date__ and __expires__ is correct. Now if you changed something inside your JS or css files, the client wouldn't get this update until the expires is done.
62 |
63 | ```html
64 |
65 | ```
66 |
67 | I added __?v0.001__ to the end of src so next time if i updated the html file and i changed __?0.001__ to something different the browser will request a new file.
68 |
69 | the same apply for css files
70 |
71 | remember because of the __.htaccess__ file we wrote above our html file will only get updated after 1week, if you wanna exclude your index from caching you can add this to your header tag.
72 |
73 | ```html
74 |
75 | ```
76 |
77 |
78 |
79 |
80 | ## Compressing your scripts:
81 | Minify and compress your files, you can use task managers like __gulp__, __grunt__ or __npm__ for the job.
82 |
83 | + Learn more about [resource minification](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#minification-preprocessing--context-specific-optimizations)
84 | + Learn more about text [compression with GZip](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#text-compression-with-gzip)
85 |
86 |
87 |
88 |
89 | ## Declare variables when needed:
90 | try to Stay away from the global lexical scope, and declare your variables exactly where you need them
91 |
92 | ```javascript
93 | // B A D
94 | let selectedBox = getSelectedBox();
95 | fetch('url')
96 | .then(res => {
97 | selectedBox.setText(res.JSON());
98 | selectedBox.unselect();
99 | })
100 | .catch(err => console.error(err.message));
101 |
102 | // B E T T E R
103 | fetch(url)
104 | .then(res => {
105 | let selectedBox = getSelectedBox();
106 | selectedBox.setText(res.JSON());
107 | selectedBox.unselect();
108 | })
109 | .catch(err => console.error(err.message));
110 | ```
111 |
112 |
113 |
114 | ## Create variable references:
115 | If you gonna use something more than once, it's much better to reference it instead of calling it from the root.
116 |
117 | ```javascript
118 | // B A D
119 | document.body.childNodes[0].data = '';
120 | document.body.childNodes[0].nodeName = '';
121 |
122 | // B E T T E R
123 | let elm = document.body.childNodes[0];
124 | elm.data = '';
125 | elm.nodeName = '';
126 | ```
127 |
128 |
129 |
130 |
131 | ## Condense variables on definition:
132 | Some compilers take less time when you use the second style.
133 |
134 | ```javascript
135 | // B A D
136 | let var1;
137 | let var2;
138 | let var3;
139 |
140 | // B E T T E R
141 | let var1, var2, var3;
142 | ```
143 |
144 |
145 |
146 | ## Always use ===
147 | ```javascript
148 | // B A D
149 | console.log(collection.length); // 10million
150 | collection.filter(item => item.status == 'on');
151 | // because typeof 'on' is String, if item.status isn't a string
152 | // the compiler will convert it to string then the comparison will start
153 | // extra step * 10 million
154 |
155 | // B E T T E R
156 | collection.filter(item => item.status === 'on');
157 |
158 | // there's much more why you should use === over ==, you google it :D
159 | ```
160 |
161 |
162 |
163 | ## Accumulate strings with arrays
164 | It's much faster.
165 |
166 | ```javascript
167 | // B A D
168 | collection.reduce((acc, user) => {
169 | return `Name: ${user.lastName} ${user.firstName}, Age: ${user.age}`;
170 | }, '');
171 |
172 | // B E T T E R
173 | collection.reduce((acc, user) => {
174 | acc.push(...user)
175 | return arr.join();
176 | }, []);
177 | ```
178 |
179 |
180 |
181 |
182 | ## Avoid Eval
183 | Just don't, except if it's 1998.
184 |
185 |
186 |
187 |
188 | ## Watch yourself when you're using closures
189 |
190 | ```javascript
191 | // B A D
192 | function fn(callback) {
193 | ajax('http://', function() {
194 | // because 'callback' is visible here
195 | // GC will never get rid of this anonumous function
196 | });
197 | callback();
198 | }
199 |
200 | // B E T T E R
201 | function func() {
202 | // now 'callback' isn't visible here
203 | }
204 | function fn(callback) {
205 | ajax('http://', func);
206 | callback();
207 | }
208 |
209 | // you can use fetch and it'll be a lot more elegant
210 | fetch('http://')
211 | .then(_ => /* do what you wanna do here */)
212 | .then(_ => /* do what you wanna do here */)
213 | ```
214 |
215 |
216 |
217 | ## Prototype for static methods
218 | I know you already know it, but mentioning it won't hurt
219 |
220 | ```javascript
221 | // B A D
222 | function City(name) {
223 | // Each city will have a different name
224 | // it's okay we gonna allocate memory so we can store the name of the city
225 | this.name = name;
226 |
227 | // this function is only responsible for getting the name of our city
228 | // so every time we create a new city object we allocate memory for
229 | // this function, wasting memory right ?
230 | this.getName = _ => this.name;
231 | }
232 |
233 | let city1 = new City('Los Angles');
234 | let city2 = new City('Atlanta');
235 | let city3 = new City('Orlando');
236 |
237 | console.log(city1.getName(), city2.getName(), city3.getName());
238 |
239 | // the location on memory of city1.getName isn't the same location
240 | // of city2.getName or city3.getName
241 | // that's why i said memory got wasted :D
242 |
243 |
244 | // B E T T E R
245 | function City(name) {
246 | this.name = name;
247 | }
248 | City.prototype.getName = _ => this.name;
249 |
250 | let city1 = new City('Los Angles');
251 | let city2 = new City('Atlanta');
252 | let city3 = new City('Orlando');
253 | console.log(city1.getName(), city2.getName(), city3.getName());
254 |
255 | // When we call 'getName' on any City object, we are referencing to
256 | // 'City.prototype.getName', that way we've saved memory
257 |
258 | ```
259 |
260 |
261 |
262 |
263 | ## Allocate only what you need
264 |
265 | ```javascript
266 | // B A D
267 | // if you're not fimilliar with reactive programming it's okay
268 | // the take away here is :
269 | // let tmp = new Array(5); only allocate what you need from memory
270 | // tmp[obj.i] = obj.data using indexing so we can assign 'data'
271 | // is faster than calling push
272 |
273 | let tmp = [];
274 | // here i'm gonna fetch (url://) 5, Every time i'm goona ask for new data
275 | // i'll push it directly into 'tmp'
276 | Rx.Observable
277 | .interval(1000)
278 | .mergeMap(_ => fetch('url://').then(res => res.JSON()))
279 | .subscribe(data => tmp.push(data))
280 | .take(5);
281 |
282 |
283 | // B E T T E R
284 | let tmp = new Array(5);
285 | Rx.Observable
286 | .interval(1000)
287 | .mergeMap(index => {
288 | return fetch('url://')
289 | .then(res => {
290 | i: index,
291 | data: res.JSON()
292 | })
293 | })
294 | .subscribe(obj => tmp[obj.i] = obj.data)
295 | .take(5);
296 | ```
297 |
298 |
299 |
300 | ## Be aware of any event, interval you add
301 | Events took so many resources when they overused,
302 | immediately call __removeEventListener()__ when you've done with any event, The same goes for intervals and timeouts
303 |
304 |
305 |
306 |
307 | ## Reduce reflow and repaint on your page
308 |
309 | Always look for ways to reduce reflow and repaint on your page, for example using __DocumentFragment__, From [MozDev](https://developer.mozilla.org/en-US/docs/DOM/document.createDocumentFragment)
310 |
311 | >Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Consequently, using document fragments often results in better performance.
312 |
313 | ```javascript
314 | // B A D
315 | let div = document.QuerySelector('div');
316 | div.appendChild(document.createTextNode("Some text"));
317 | div.appendChild(document.createElement("br"));
318 | div.appendChild(document.createElement("a"));
319 | document.body.appendChild(div);
320 |
321 | // B E T T E R
322 | let frag = document.createDocumentFragment();
323 | frag.appendChild(document.createTextNode("Some text"));
324 | frag.appendChild(document.createElement("br"));
325 | fragdiv.appendChild(document.createElement("a"));
326 | document.body.appendChild(frag);
327 |
328 | // you can also use es6 template literals + HTML and would be a lot more faster
329 | // just imagine duplicating a node element vs duplicating a string (html) text
330 | // a lot more fluid and agile, you can use all your string manipulation skills
331 | ```
332 |
333 |
334 |
335 |
336 | ## async & deffer
337 |
338 | I can't explain it better than this : [async vs defer attributes](http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html)
339 |
340 |
341 |
342 |
343 | ## to be continue
344 |
--------------------------------------------------------------------------------