|
| 1 | +## In this demo we are going to work with Web Workers. |
| 2 | +* Folder structure: |
| 3 | + |
| 4 | +09 Web Workers/ |
| 5 | +├── src/ |
| 6 | +│ ├── content/ |
| 7 | +| | ├── site.css |
| 8 | +│ ├── js/ |
| 9 | +| | ├── inline.js |
| 10 | +| | ├── crunchNumbers.js |
| 11 | +| | ├── background.js |
| 12 | +│ ├── index.html |
| 13 | +│ └── bootstrap-theme.min.css |
| 14 | +├── gulpfile.js |
| 15 | +├── package.json |
| 16 | + |
| 17 | +* Start from previous code demo. |
| 18 | + |
| 19 | +## Steps. |
| 20 | + |
| 21 | +### 1. Refactor the `index.html` for our demo. |
| 22 | + |
| 23 | +* Just paste this code. |
| 24 | + |
| 25 | +```diff html |
| 26 | +<!doctype html> |
| 27 | + |
| 28 | +<html lang="en"> |
| 29 | +<head> |
| 30 | + <meta charset="utf-8"> |
| 31 | + <title>LEMONCODE 16/17 jQuery</title> |
| 32 | + <link rel="stylesheet" href="content/site.css"> |
| 33 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 34 | +</head> |
| 35 | + |
| 36 | +<body> |
| 37 | + <h1>API Rest</h1> |
| 38 | ++ <!-- HTML5 element to show progress --> |
| 39 | ++ <progress id="worker-progress" value="0" max="100"></progress> |
| 40 | +</body> |
| 41 | +</html> |
| 42 | + |
| 43 | +``` |
| 44 | + |
| 45 | +### 2. Lets change our `site.css`, for this demo. |
| 46 | + |
| 47 | +```diff site.css |
| 48 | +@import url('https://fonts.googleapis.com/css?family=Raleway'); |
| 49 | + |
| 50 | +body { |
| 51 | + font-family: 'Raleway', sans-serif; |
| 52 | +} |
| 53 | + |
| 54 | +.container { |
| 55 | + padding: 2em; |
| 56 | +} |
| 57 | + |
| 58 | +.container p { |
| 59 | + max-width: 70%; |
| 60 | + font-size: 0.9em; |
| 61 | + margin-top: 0.2em; |
| 62 | + margin-bottom: 0.2em; |
| 63 | + height: 2.3em; |
| 64 | +} |
| 65 | + |
| 66 | +.container p img { |
| 67 | + max-width: 95%; |
| 68 | + max-height: 95%; |
| 69 | + position: relative; |
| 70 | + top: 0.7em; |
| 71 | + left: 1em; |
| 72 | +} |
| 73 | + |
| 74 | +.container ul { |
| 75 | + list-style: none; |
| 76 | +} |
| 77 | + |
| 78 | ++progress { |
| 79 | ++ width: 80%; |
| 80 | ++ height: 20px; |
| 81 | ++ -webkit-appearance: none; |
| 82 | ++} |
| 83 | ++ |
| 84 | ++progress::-webkit-progress-bar { |
| 85 | ++ background: lightgrey; |
| 86 | ++ border-radius: 50px; |
| 87 | ++ border: 1px solid gray; |
| 88 | ++} |
| 89 | ++ |
| 90 | ++progress::-webkit-progress-value { |
| 91 | ++ background: #31C6F7; |
| 92 | ++ border-radius: 50px; |
| 93 | ++} |
| 94 | ++ |
| 95 | +``` |
| 96 | +### 3. Lets start by creating a new script and watch the effects on browser. |
| 97 | + |
| 98 | +```diff index.html |
| 99 | +<!doctype html> |
| 100 | + |
| 101 | +<html lang="en"> |
| 102 | +<head> |
| 103 | + <meta charset="utf-8"> |
| 104 | + <title>LEMONCODE 16/17 jQuery</title> |
| 105 | + <link rel="stylesheet" href="content/site.css"> |
| 106 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 107 | +</head> |
| 108 | + |
| 109 | +<body> |
| 110 | + <h1>API Rest</h1> |
| 111 | + <!-- HTML5 element to show progress --> |
| 112 | + <progress id="worker-progress" value="0" max="100"></progress> |
| 113 | + |
| 114 | ++ <script src="./js/inline.js"></script> |
| 115 | +</body> |
| 116 | +</html> |
| 117 | + |
| 118 | +``` |
| 119 | + |
| 120 | +```javascript inline.js |
| 121 | +(() => { |
| 122 | + const longTask = (progressCalback) => { |
| 123 | + for (let step = 0; step < 10; step++) { |
| 124 | + progressCalback(step * 10); |
| 125 | + /* |
| 126 | + Use the developer tools to show that the console log is not blocked |
| 127 | + */ |
| 128 | + console.log(step); |
| 129 | + const start = Date.now(); |
| 130 | + const seconds = 1; |
| 131 | + const waitUntil = start + seconds * 1000; |
| 132 | + while (Date.now() < waitUntil) {} |
| 133 | + } |
| 134 | + }; |
| 135 | + |
| 136 | + const progress = document.getElementById('worker-progress'); |
| 137 | + |
| 138 | + longTask((percentage) => { |
| 139 | + progress.value = percentage; |
| 140 | + }); |
| 141 | +})(); |
| 142 | + |
| 143 | + |
| 144 | +``` |
| 145 | +* We have the element progress. |
| 146 | +* We have `longTask`, that will update the screen on its feed it `callback`. |
| 147 | +* `longTask` performances an intensive task blocking the UI around 1 second. |
| 148 | +* How many little programs are? -> `2` |
| 149 | + |
| 150 | +> NOTE: Use developer tools to watch that the console does not get blocked. |
| 151 | +
|
| 152 | +* We can watch in `console.log(step)`, how it's getting updated when we get a new step value, but the UI it's not getting updated. This is because it's not to get updated until, the code block ends (`for statement`). |
| 153 | + |
| 154 | +* Let's write this with a web worker to avoid this issue. |
| 155 | + |
| 156 | +### 4. We have to create two new files in order to use a Web Worker. |
| 157 | + |
| 158 | +```javascript longTask.js |
| 159 | +const longTask = (progressCalback) => { |
| 160 | + for (let step = 0; step < 10; step++) { |
| 161 | + progressCalback(step * 10); |
| 162 | + /* |
| 163 | + Use the developer tools to show that the console log is not blocked |
| 164 | + */ |
| 165 | + console.log(step); |
| 166 | + const start = Date.now(); |
| 167 | + const seconds = 1; |
| 168 | + const waitUntil = start + seconds * 1000; |
| 169 | + while (Date.now() < waitUntil) {} |
| 170 | + } |
| 171 | +}; |
| 172 | + |
| 173 | +longTask(postMessage); |
| 174 | + |
| 175 | +``` |
| 176 | + |
| 177 | +```javascript background.js |
| 178 | +(() => { |
| 179 | + const progress = document.getElementById('worker-progress'); |
| 180 | + |
| 181 | + const longTaskWorker = new Worker('./js/longTask.js'); |
| 182 | + |
| 183 | + longTaskWorker.onmessage = (message) => { |
| 184 | + progress.value = message.data; |
| 185 | + }; |
| 186 | +})(); |
| 187 | +``` |
| 188 | + |
| 189 | +* `longTask(postMessage);` El callback que le pasamos es un método del propio worker (el worker inyecta el callback) que al ser invocado el statement: `progressCallback(step * 10);` manda el mensaje, que recibe el worker `worker.onmessage`. La comunicación puede ser bidireccional. |
| 190 | + |
| 191 | +* NOTA: NO tiene acceso al DOM. |
| 192 | + |
| 193 | +### REFERENCE https://developer.mozilla.org/es/docs/Web/Guide/Performance/Usando_web_workers |
| 194 | + |
| 195 | +* Now we can change `index.html`, to watch results. |
| 196 | + |
| 197 | +```diff index.html |
| 198 | +<!doctype html> |
| 199 | + |
| 200 | +<html lang="en"> |
| 201 | +<head> |
| 202 | + <meta charset="utf-8"> |
| 203 | + <title>LEMONCODE 16/17 jQuery</title> |
| 204 | + <link rel="stylesheet" href="content/site.css"> |
| 205 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 206 | +</head> |
| 207 | + |
| 208 | +<body> |
| 209 | + <h1>API Rest</h1> |
| 210 | + <!-- HTML5 element to show progress --> |
| 211 | + <progress id="worker-progress" value="0" max="100"></progress> |
| 212 | + |
| 213 | ++ <script src="./js/background.js"></script> |
| 214 | +- <script src="./js/inline.js"></script> |
| 215 | +</body> |
| 216 | +</html> |
| 217 | + |
| 218 | +``` |
| 219 | +* En conclusión, uando el web worker se ejecuta, crunchNumbers es llamado, postMessage es la función que se usa para mandar mensajesal principal, el engine de JavaScript que controla la UI. |
| 220 | +* Este ejemplo de IPC, en realidad no lo es. Este web workerque hemos creado con new, es un web worker dedicado, sólo es un thread que se ejecuta dentro del mismo proceso, pero aún así tenemos cierta separación entre la ejecución del JavaScript que esta ejcutando estos workers. |
| 221 | +* Existe una asincronicidad debido a la separación de hilos. Los shared workers, si ejecutan sus propios procesos, y son un ejemplo claro de IPC. |
0 commit comments