You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 2-ui/99-ui-misc/03-event-loop/article.md
+49-49Lines changed: 49 additions & 49 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,20 +3,20 @@
3
3
4
4
Sia il flusso di esecuzione di Javascript, che quello di Node.js, sono basati sull' *event loop*.
5
5
6
-
Comprendere come funziona un event loop è importante sia per una question di ottimizzazione dell'esecuzione del codice, ma a volte, anche per creare delle architetture migliori.
6
+
Comprendere come funziona un event loop è importante sia per una questione di ottimizzazione dell'esecuzione del codice, ma a volte, anche per creare delle architetture software migliori.
7
7
8
-
In questo capitolo affronteremo l dettagli teorici sul funzionanento, dopodichè prenderemo in esame alcune applicazioni pratiche.
8
+
In questo capitolo affronteremo i dettagli teorici sul funzionanento, dopodichè prenderemo in esame alcune applicazioni pratiche.
9
9
10
10
## Event Loop
11
11
12
-
Il concetto di *event loop*è molto semplice. Esiste un loop infinito, nel quale il motore di Javascript rimane in attesa di un task (compito, operazione) da eseguire, lo esegue, dopodichè si rimette in attesa per altri tasks. (rimane in sleep, inattivo o dormiente, ma pronto per essere di nuovo richiamato).
12
+
Il concetto di *event loop*è molto semplice. Esiste un loop infinito, nel quale il motore di Javascript rimane in attesa di un task (compito o operazione da eseguire), lo esegue, quindi si mette in attesa per altri tasks (rimane in sleep, inattivo o dormiente, ma pronto per essere di nuovo richiamato).
13
13
14
14
A grandi linee, l'algoritmo del motore è così:
15
15
1. Fino a quando ci sono task:
16
16
- eseguili, cominciando da quello meno recente.
17
17
2. Rimani in attesa fino a quando non c'è un altro task da eseguire, quindi vai al passo 1.
18
18
19
-
Questa è una trasposizione di quello che vediamo quando navighiamo in una pagina web. Il motore di Javascript non fa nulla per la maggior parte del tempo, e va in esecuzione quando si attiva uno script/handler/evento.
19
+
Questa è una trasposizione di quello che vediamo mentre navighiamo in una pagina web. Il motore di Javascript non fa nulla per la maggior parte del tempo, e va in esecuzione quando si attiva uno script/handler/evento.
20
20
21
21
Esempio di tasks:
22
22
@@ -44,30 +44,30 @@ Ancora due dettagli:
44
44
1. Il rendering non avviene mai quando il motore sta eseguendo un task. Non importa se questo impiega molto tempo. I cambiamenti al DOM vengono renderizzati (ridisegnati sul browser) solo dopo che il task viene completato.
45
45
2. Se un task impiega troppo tempo, il browser non puiò eseguire altri tasks, processare altri eventi utente, e così dopo un certo periodo di tempo viene scaturito un alert di "Pagina bloccata" (Page Unresponsive) che ci suggerisce di terminare il task e l'intera pagina. Questo succede in concomitanza di una serie di calcoli complessi, o in seguito ad errori di programmazione che portano loop infiniti.
46
46
47
-
Questa era la teoria, ma vediamo come applicare questi concetti.
47
+
Ok, questa era la teoria, ma vediamo come mettere in pratica questi concetti.
48
48
49
49
## Caso d'uso 1: Spezzettamento di task affamati di CPU (processi intensivi)
50
50
51
-
Poniamo il caso che abbiamo un task affamato di CPU.
51
+
Poniamo il caso che abbiamo un task affamato di CPU (CPU-hungry process).
52
52
53
53
Per esempio, la syntax-highlighting (usata per colorare ed evidenziare gli esempi del codice in questa pagina) è abbastanza pesante per la CPU.
54
54
Per evidenziare il codice, compie delle analisi, crea molti elementi colorati, e li aggiunge al documento -- un testo di grosse dimensioni può impiegare molto tempo.
55
55
56
-
Mentre il motore è occupato con l'evidenziatura, non può fare le altre cose relative al DOM, processare gli eventi dell'utente, etc. può persino causare "singhiozzamenti" al pc o addirittura "inchiodarlo", la qual cosa è inaccettabile.
56
+
Mentre il motore è occupato con l'evidenziatura, non può fare altre cose relative al DOM, processare gli eventi dell'utente, etc. può, può persino causare "singhiozzamenti" al pc o addirittura "inchiodarlo", la qual cosa è inaccettabile.
57
57
58
-
Possiamo quindi tirarci fuori da questo tipo di problemi, spezzettando i task grossi in piccoli pezzi. Evidenzia le prime 100 righe, quindi schedula un `setTimeout` (con zero-delay) con altre 100 righe, e così via fino alla fine.
58
+
Possiamo quindi tirarci fuori da questo tipo di problemi, spezzettando i task grossi in piccoli pezzi da eseguire. Evidenzia le prime 100 righe, quindi schedula un `setTimeout` (con zero-delay) con altre 100 righe, e così via fino alla fine.
59
59
60
60
Per dimostrare questo tipo di approccio, e per amore della semplicità, anzichè evidenziare una sintassi, prendiamo una funzione che conti i numeri da `1` a `1000000000`
61
61
62
-
Se esegui il codice sotto, il motore si inchioderà per qualche istante. Per il JS server-side (lato server) questo è chiaramente visibile, ma se lo stai eseguendo nella finestra del browser, provando a cliccare gli altri pulsanti -- potrai notare che non verrà gestito nessun altro evento fino a quando il conto non sarà terminato.
62
+
Se esegui il codice sotto, il motore si inchioderà per qualche istante. Per il JS server-side (lato server) questo è chiaramente visibile, ma se lo stai eseguendo nella finestra del browser, provando a cliccare gli altri pulsanti -- potrai notare che non verrà gestito nessun altro evento fino a quando il conteggio dei numeri non sarà terminato.
63
63
64
64
```js run
65
65
let i =0;
66
66
67
67
let start =Date.now();
68
68
69
69
functioncount() {
70
-
//fa un lavoro pesante!
70
+
//un lavoro pesante!
71
71
for (let j =0; j <1e9; j++) {
72
72
i++;
73
73
}
@@ -80,15 +80,15 @@ count();
80
80
Il browser potrebbe anche mostrare l'avviso "lo script sta impiegando troppo tempo" the script takes too long".
81
81
82
82
83
-
Ora, dividiamo l'operazione con l'ausilio di un `setTimeout` annidato:
83
+
Ora invece, dividiamo l'operazione con l'ausilio di un `setTimeout` annidato:
84
84
85
85
```js run
86
86
let i =0;
87
87
88
88
let start =Date.now();
89
89
90
90
functioncount() {
91
-
//fai una parte del lavoro pesante (*)
91
+
//fai una parte del lavoro pesante :-) (*)
92
92
do {
93
93
i++;
94
94
} while (i %1e6!=0);
@@ -110,13 +110,13 @@ Una singola esecuzione di `count` fa una parte dell'operazione `(*)`, e rischedu
110
110
2. La seconda esecuzione conta: `i=1000001..2000000`.
111
111
3. ...e così via.
112
112
113
-
Ora, se arriva un nuovo task da eseguire mentre il motore è occupato ad eseguire il passo 1 (ad esempio un evento `onclick`), quest'ultimo viene messo in coda e viene eseguito subito dopo il completamento del passo 1, e subito prima del passo successivo. Questi periodici "ritorni" all'event loop tra una esecuzione di `count` e l'altra, fornisce abbastanza "aria" al motore Javascript per occuparsi di qualcos'altro, ad esempio per reagire alle azioni degli utenti.
113
+
Ora, se arriva un nuovo task da eseguire mentre il motore è occupato ad eseguire il passo 1, poniamo il caso ad esempio che venga sollevato un evento `onclick`, quest'ultimo viene messo in coda ed eseguito subito dopo il completamento del passo 1, ma subito prima del passo successivo. Questi periodici "ritorni" all'event loop tra una esecuzione di `count` e l'altra, fornisce abbastanza "respiro" al motore Javascript per occuparsi di qualcos'altro, ad esempio per reagire alle azioni degli utenti.
114
114
115
115
La cosa ragguardevole è che entrambe le varianti -- con e senza la divsione del lavoro di `setTimeout` -- sono comparabili in termini di tempo. Complessivamente, non esiste molta differenza nel tempo di conteggio.
116
116
117
-
Per renderli un po' più facciamo un miglioramento.
117
+
Per renderli un po' piùpiù comparabili, facciamo un miglioramento.
118
118
119
-
Posizioneremo la schedualzione all'inizio del `count()`:
119
+
Posizioniamo la schedulazione all'inizio del `count()`:
120
120
121
121
122
122
```js run
@@ -139,25 +139,26 @@ function count() {
139
139
count();
140
140
```
141
141
142
-
Adesso quando cominciamo con `count()` e vediamo che abbiamo bisogno di richiamarlo più`count()`, lo scheduliamo subito, prima di fare il lavoro.
142
+
Adesso, quando cominciamo con `count()` e vediamo che abbiamo bisogno di richiamarlo più`count()`, lo scheduliamo subito prima di fare il lavoro.
143
143
144
-
Se lo esegui, è facile notare che impiega meno tempo in modo significativo.
144
+
Se lo esegui, è facile notare che impiega significativamente meno tempo.
145
145
146
146
147
147
Perchè?
148
148
149
-
Semplice: come ben sai, c'è un ritardo minimo di 4ms all'interno del browser per molte chiamate annidate di `setTimeout`. Anche se noi lo settiamo `0`, sarà di `4ms` (o qualcosa in più). Quindi, prima lo scheduliamo, più veloce sarà l'esecuzione.
150
-
Alla fine, abbiamo diviso un task affamato di CPU in porzioni - e adesso non bloccherà l'interfaccia utente. E il suo tempo di esecuzione complessivo non è tanto più lungo.
149
+
Semplice: come saprai, c'è un ritardo minimo di 4ms all'interno del browser per tantissime chiamate annidate di `setTimeout`. Anche se noi lo abbiamo impostato a `0`, sarà di `4ms` (o qualcosa in più). Quindi, prima lo scheduliamo, più veloce sarà l'esecuzione.
150
+
Alla fine, abbiamo diviso un task affamato di CPU in porzioni - che adesso non bloccherà più l'interfaccia utente. Inoltre, il suo tempo di esecuzione complessivo non è tanto più lungo.
151
+
151
152
152
153
## Caso d'uso 2: Indicazione dei progressi di una operazione
153
154
154
-
Un altro beneficio di dividere task pesanti per gli script del browser è che possiamo mostrare i progressi di completamento.
155
+
Un altro beneficio nel dividere task pesanti per gli script del browser è che possiamo mostrare i progressi di completamento.
155
156
156
157
Solitamente il browser renderizza dopo che il codice in esecuzine viene completato. Non importa se il task impiega tanto tempo. Le modifice al DOM vengono mostrate solo dopo che il task è terminato.
157
158
158
-
Da una parte, questo è grandioso, perchè la nostra fuznione può molti elementi, aggiungerli uno alla volta al documento e cambiarne gli stili -- il visitatorenon vorrebbe mai vedere uno stadio "intermedio", incompleto. Una cosa importante, giusto?
159
+
Da una parte, questo è grandioso, perchè la nostra funzione puòcreare molti elementi, aggiungerli uno alla volta al documento e cambiarne gli stili -- il visitatore, d'altra parte, non vorrebbe mai vedere uno stadio "intermedio" ed incompleto. Una cosa importante, giusto?
159
160
160
-
Qui c'è la demo, i cambiamenti a`i` non verrano mostrati fino a quando la funzione nno termina, così vedremo solamente l'ultimo valore:
161
+
Con l'esempio qui sotto abbiamo una dimostrazione, le modifiche all'elemento che rappresenta i valori di`i` non verrano mostrati fino a quando la funzione non termina, così vedremo solamente il valore definitivo:
161
162
162
163
```html run
163
164
<divid="progress"></div>
@@ -175,9 +176,9 @@ Qui c'è la demo, i cambiamenti a `i` non verrano mostrati fino a quando l
175
176
</script>
176
177
```
177
178
178
-
...Però potremmo volere mostrare qualcosa durante il task, ad esempio una barra di progresso.
179
+
...Tuttavia; potremmo voler mostrare qualcosa durante il task, ad esempio una barra di progresso.
179
180
180
-
Se noi dividiamo il task pesante in pezzi usando `setTimeout`, allora tra essi, verranno mostrate le variazioni.
181
+
Se andiamo a dividere il task pesante in pezzi usando `setTimeout`, allora tra ognuno di essi, verranno mostrate delle variazioni.
181
182
182
183
Questo sembra più carino:
183
184
@@ -205,21 +206,20 @@ Questo sembra più carino:
205
206
</script>
206
207
```
207
208
208
-
Adesso il `<div>` mostra via via, valori crescenti di `i`,come se fosse una sorta di barra di caricamento.
209
+
Adesso il `<div>` mostra valori sempre crescenti di `i`,come se fosse una sorta di barra di caricamento.
209
210
210
211
211
212
## Caso d'uso 3: fare qualcosa dopo l'evento
212
213
213
-
In un gestore di evento, potremmo decidere di postporre alcune azioni, fino a che l'evento non risalga i vari livelli di stack (bubbling up) e non venga gestito su tutti questi livelli.
214
-
Possiamo farlo, avvolgendo (wrapping) il codice all'interno dei`setTimeout` a ritardo zero.
214
+
In un gestore di evento, potremmo decidere di postporre alcune azioni, fino a che l'evento non risalga i vari livelli dello stack (bubbling up) e non venga gestito su tutti questi livelli.
215
+
Possiamo farlo, avvolgendo (wrapping) il codice all'interno di istruzioni`setTimeout` a ritardo zero.
215
216
216
-
Nel capitolo <info:dispatch-events> abbiamo visto un esempio: dell'evento custom `menu-open`, viene fatto il dispatch dentro `setTimeout`, così che esso viene richiamato dopo che l'evento click èstto del tutto gestito.
217
+
Nel capitolo <info:dispatch-events> abbiamo visto un esempio: dell'evento custom `menu-open`, viene fatto il dispatch dentro `setTimeout`, così che esso viene richiamato dopo che l'evento click èstato del tutto gestito.
217
218
218
219
219
220
```js
220
221
menu.onclick=function() {
221
222
// ...
222
-
223
223
//crea un evento custom con l'elemento dati cliccato sul menu'
224
224
let customEvent =newCustomEvent("menu-open", {
225
225
bubbles:true
@@ -230,16 +230,16 @@ menu.onclick = function() {
230
230
};
231
231
```
232
232
233
-
## Macrotasks e Microtasks
234
233
234
+
## Macrotasks e Microtasks
235
235
236
-
insieme ai *macrotasks*, descritti in questo capitolo, esistono i *microtasks*, menzionati nel capitolo <info:microtask-queue>.
236
+
Insieme ai *macrotasks*, descritti in questo capitolo, esistono i *microtasks*, menzionati nel capitolo <info:microtask-queue>.
237
237
238
-
Microtasks provengono esclusivamente dal nostro codice. Solitamente vengono creati dalle promises: una esecuzione di un gestore `.then/catch/finally` diventa un microtask. I microtasks vengono usati anche "sotto copertura" dagli `await`, dato che anche questi sono solo un'altra forma di gestione delle promise.
238
+
I microtasks provengono esclusivamente dal nostro codice. Solitamente vengono creati dalle promises: una esecuzione di un gestore `.then/catch/finally` diventa un microtask. I microtasks vengono usati anche "sotto copertura" dagli `await`, dato che anche questi non sono altro che un'altra forma di gestione di promises.
239
239
240
-
C'è anche una funzione speciale `queueMicrotask(func)` che accoda `func`per l'esecuzione nella coda dei microtask.
240
+
C'è anche una funzione speciale `queueMicrotask(func)` che accoda `func`per l'esecuzione nella coda dei microtask.
241
241
242
-
**Immediatamente dopo ogni *macrotask*, il motore esegue tutti i task dalla coda *microtask* queue, prima di ricominciare a eseguire ogni altro macrotask o renderizzare o qualunque altra cosa.**
242
+
**Immediatamente dopo ogni *macrotask*, il motore esegue tutti i task dalla coda *microtask*, prima di ricominciare a eseguire ogni altro macrotask o renderizzare o qualunque altra cosa.**
243
243
244
244
Per esempio, guardate questo:
245
245
@@ -252,24 +252,24 @@ Promise.resolve()
252
252
alert("code");
253
253
```
254
254
255
-
Che sta succedendo all'ordine qui?
255
+
Cosa succederàall'ordine delle operazioni in questo script?
256
256
257
-
1.`code` viene mostrato prima, dato che è un chiamata regolare e sincrona.
257
+
1.`code` viene mostrato per primo, dato che è un chiamata regolare e sincrona.
258
258
2.`promise` viene mostrato per secondo, perchè`.then` passa attraverso la coda di microtask, e viene eseguito dopo il codice corrente.
259
259
3.`timeout` viene mostrato come ultimo perchèè anhe questo un microtask.
260
260
261
-
L'immagine più esausitva di un event loop èèquesta:
261
+
L'immagine più esausitva di un event loop è questa:
262
262
263
263

264
264
265
265
**Tutti i microtasks vengono completati prima di ogni altra gestione degli eventi o rendering o qualunque altro macrotask che prende parte nell'esecuzione**
266
266
267
-
Questo è importante perchè garantisce che l'ambiente applicativo rimanga intatto (nessuna modifica alle coordinate del puntatore del mouse, nessun dato dalle reti, etc) tra i microtasks.
267
+
Questo è importante perchè garantisce che l'ambiente applicativo rimanga intatto (nessuna modifica alle coordinate del puntatore del mouse, nessun dato dalle reti, etc) tra i vari microtasks.
268
268
269
-
Se volessimo eseguire una funzione in maniera asincrona (dopo il codice in esecuzione), ma prima che avvengano cambiamenti nella finestra del browser, o nuvi eventi vengano gestiti, potremmo schedularla con `queueMicrotask`.
269
+
Se volessimo eseguire una funzione in maniera asincrona (dopo il codice in esecuzione), ma prima che avvengano cambiamenti nella finestra del browser, o che nuovi eventi vengano gestiti, potremmo schedularla con `queueMicrotask`.
270
270
271
-
Questo qui un esempio con la "conteggio barra di progresso", del tutto simi a quella precedente, ma vengono usati `queueMicrotask` invece di `setTimeout`.
272
-
Come puoi vedere che renderizza alla fine. Esattamente come se fosse del codice sincrono:
271
+
Questo qui èun esempio della funzion "conteggio barra di progresso", del tutto simile alla precedente, ma vengono usati `queueMicrotask` invece di `setTimeout`.
272
+
Come puoi notare, renderizza il valore del conteggio alla fine. Esattamente come se fosse del codice sincrono:
273
273
274
274
```html run
275
275
<divid="progress"></div>
@@ -299,7 +299,7 @@ L'immagine più esausitva di un event loop è questa:
299
299
300
300

301
301
302
-
Il più dettagliato algoritmo dell'event loop (sebbene ancora semplicistico rispetto alla [specification](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)):
302
+
Questo è il più dettagliato algoritmo dell'event loop: (sebbene ancora semplicistico rispetto alla [specification](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)):
303
303
304
304
1. Rimuovi dalla coda ed esegui il task meno recente dalla coda dei *macrotask* (ad esempio "script").
305
305
2. Esegui tutti i *microtasks*:
@@ -310,26 +310,26 @@ Il più dettagliato algoritmo dell'event loop (sebbene ancora semplicistic
310
310
5. Vai al passo 1.
311
311
312
312
Per schedulare un nuovo *macrotask*:
313
-
-Use zero delayed `setTimeout(f)`.
313
+
-Usa un `setTimeout(f)` ritardo zero.
314
314
315
-
Questo potrebbe essere usato per divitere task di calcolopesante in pezzi, di modo che tra questi, il browser possa eseguire altre operazioni.
315
+
Questo potrebbe essere usato per divitere task di calcolo pesante in pezzi più piccoli, di modo che nello spazio tra questi, il browser possa eseguire altre operazioni.
316
316
317
317
Inoltre, vengono usati nei gestori degli eventi per schedulre una azione dopo che l'evento è stato del tutto gestito (bubbling completato)
318
318
319
319
Per schedulare un nuovo *microtask*
320
320
- Usa `queueMicrotask(f)`.
321
321
- Anche i gestori promise passando attraverso la coda dei microtask.
322
322
323
-
Non ci sono gestori UI o di networking tra i microtask: vengono eseguiti immediatamente uno dopo l'altro
323
+
Non ci possono essere gestioni di UI o di networking tra i microtask, perchè i microtasks vengono eseguiti immediatamente uno dopo l'altro.
324
324
325
-
Quindi uno potrebbe volere che la coda `queueMicrotask` eseguisse una funzione in maniera asincrona, ma manntenendo il contesto dell'ambiente.
325
+
Ma cosa succederebbe se uno volesse che la coda `queueMicrotask` eseguisse una funzione in maniera asincrona, mantenendo però il contesto dell'ambiente.
326
326
327
327
```smart header="Web Workers"
328
328
Per lunghi calcoli pesanti che non possono bloccare l'event loop, possiamo usare i [Web Workers](https://html.spec.whatwg.org/multipage/workers.html).
329
329
330
-
Che è un modo per eseguire del codice in un altro thread parallelo.
330
+
I Web Workers sono un modo per eseguire del codice in un altro thread parallelo.
331
331
332
-
I Web Workers possono scambiarsi messaggi con il processo principale, ma hanno le loro variabili ed i loro event loop.
332
+
I Web Workers possono scambiare messaggi con il processo principale, ma hanno le loro variabili ed i loro event loop.
333
333
334
-
I Web Workers non hanno accesso al DOM, quindi sono adatti principalmente per i calcoli, per usare contemporaneamente più cores CPU.
334
+
I Web Workers non hanno accesso al DOM, quindi sono adatti principalmente per i calcoli, per usare contemporaneamente più cores della CPU.
0 commit comments