├── 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 | ![logo](http://3.bp.blogspot.com/-PTty3CfTGnA/TpZOEjTQ_WI/AAAAAAAAAeo/KeKt_D5X2xo/s1600/js.jpg "JS logo") 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 | ![img1](http://i.imgur.com/wa2iUOc.png) 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 | --------------------------------------------------------------------------------