-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy path07s-latency-compensation.md.erb
133 lines (93 loc) · 7.19 KB
/
07s-latency-compensation.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
---
title: Compensazione della latenza
slug: latency-compensation
date: 0007/01/02
number: 7.5
sidebar: true
contents: Capire la compensazione di latenza.|Rallentare la costruzione l'applicazione per capire meglio come funziona.|Capire come i metodi di Meteor si chiamano tra di loro.
paragraphs: 28
---
Nell'ultimo capitolo abbiamo introdotto un nuovo concetto nell'universo di Meteor: i **Metodi**.
<%= diagram "latency1", "Without latency compensation", "pull-right" %>
Un Metodo di Meteor è un modo per eseguire una serie di comandi sul server in maniera strutturata. Nel nostro esempio abbiamo usato un Metodo perché vogliamo che i nuovi post siano taggati con il nome e l'id dell'autore e con l'orario corrente del server.
Tuttavia se Meteor eseguisse i Metodi nel modo più semplice avremmo un problema. Considerate questa sequenza di eventi (nota: i timestamp sono valori casuali presi per semplice scopo illustrativo):
- *+0ms:* L'utente clicca su un bottone di submit e il browser scatena una chiamata al Metodo.
- *+200ms:* Il server esegue le modifiche sul database di Mongo.
- *+500ms:* Il client riceve le modifiche e aggiorna l'interfaccia utente per visualizzarle.
Se questo fosso il modo in cui funziona Meteor ci sarebbe un breve ritardo tra l'esecuzione di queste azioni e il risultato (il ritardo sarebbe più o meno sensibile, dipende da quanto vicini siete al server). Non è accettabile in una moderna applicazione web!
### Compensazione di latenza
<%= diagram "latency2", "With latency compensation", "pull-right" %>
Per evitare questo problema, Meteor introduce un concetto chiamato **Compensazione di latenza**. Quando abbiamo definito il nostro Metodo `post`, l'abbiamo messo un un file nella cartella `collections/`. Questo significa che è disponibile sia sul server che *sul client* -- e verrà eseguito su entrambi allo stesso tempo!
Quando fate una chiamata a un Metodo, il client invia la chiamata al server, ma contemporaneamente *simula* l'azione del Metodo sulle collezioni del client. Il processo ora è questo:
- *+0ms:* L'utente clicca su un bottone di submit e il browser scatena una chiamata al Metodo.
- *+0ms:* Il client simula l'azione della chiamata al Metodo sulle collezioni lato client e aggiorna l'interfaccia per visualizzarle.
- *+200ms:* Il server esegue le modifiche sul database di Mongo.
- *+500ms:* Il client riceve le modifiche e annulla le modifiche simulate rimpiazzandole con quelle del server (che sono di solito le stesse). L'interfaccia si modifica per visualizzarle.
Questo fa in modo che l'utente veda le modifiche istantaneamente. Quanto la risposta del server arriva qualche momento più tardi, possono esserci o meno delle modifiche sensibili ai documenti che il server invia. Una cosa da imparare è che dovete cercare di simulare i reali documenti il più fedelmente possibile.
### Osservare la compensazione di latenza
Possiamo fare una piccola modifica alla chiamate del Metodo `post` per vederlo in azione. Per farlo dovremo fare un po' di codice avanzato con il pacchetto npm `futures` per ritardare l'inserimento di oggetti nel nostro Metodo.
Useremo `isSimulation` per chiedere a Meteor se il Metodo è chiamato come un abbozzo. Un [abbozzo](http://docs.meteor.com/#methods_header) è la simulazione di un Metodo che Meteor esegue sul client in parallelo, mentre il Metodo "reale" viene eseguito sul server.
In questo modo chiediamo a Meteor se il codice si sta eseguendo sul client. Se è così aggiungiamo la stringa `(client)` alla fine del titolo del post. Se non è così, aggiungiamo la stringa `(server)`:
~~~js
Meteor.methods({
post: function(postAttributes) {
// […]
// pick out the whitelisted keys
var post = _.extend(_.pick(postAttributes, 'url', 'message'), {
title: postAttributes.title + (this.isSimulation ? '(client)' : '(server)'),
userId: user._id,
author: user.username,
submitted: new Date().getTime()
});
// wait for 5 seconds
if (! this.isSimulation) {
var Future = Npm.require('fibers/future');
var future = new Future();
Meteor.setTimeout(function() {
future.return();
}, 5 * 1000);
future.wait();
}
var postId = Posts.insert(post);
return postId;
}
});
~~~
<%= caption "collections/posts.js" %>
<%= highlight "6, 7, 13~22" %>
Nota: in caso ve lo stiate chiedendo, il `this` in `this.isSimlation` è un [oggetto di invocazione di Metodo](http://docs.meteor.com/#meteor_methods) che provvede accesso a svariate e utili variabili.
Come funziona esattamente [Futures](https://npmjs.org/package/future) esula dagli argomenti di questo libro, ma abbiamo praticamente detto a Meteor di aspettare 5 secondi prima di inserire il documento nella collezione sul server.
Abbiamo fatto anche un reindirizzamento alla lista di post:
~~~js
Template.postSubmit.events({
'submit form': function(event) {
event.preventDefault();
var post = {
url: $(event.target).find('[name=url]').val(),
title: $(event.target).find('[name=title]').val(),
message: $(event.target).find('[name=message]').val()
}
Meteor.call('post', post, function(error, id) {
if (error)
return alert(error.reason);
});
Router.go('postsList');
}
});
~~~
<%= caption "client/views/posts/post_submit.js" %>
<%= highlight "15" %>
<%= scommit "7-5-1", "Demonstrate the order that posts appear using a sleep." %>
Se creiamo un post ora vedremo la compensazione di latenza in azione. Prima viene inserito un post con `(client)` nel titolo (il primo post nella lista che rimanda a GitHub):
<%= screenshot "s5-1", "Our post as first stored in the client collection" %>
Cinque secondi più tardi, viene rimpiazzato dal domento reale che è stato inserito sul server:
<%= screenshot "s5-2", "Our post once the client receives the update from the server collection" %>
### Metodi delle collezioni sul client
Potete pensare che i Metodi siano complicati dopo di questo, ma in realtà possono essere abbastanza semplici. Abbiamo visto tre semplici Metodi finora: i Metodi dei cambiamenti in una collezione, `insert`, `update` e `remove`.
Quando definite una collezione sul server chiamata `'posts'`, state implicitamente definendo tre Metodi: `posts/insert`, `posts/update` and `posts/delete`. In altre parole, quando chiamate `Posts.insert()` sulla vostra collezione lato client, state eseguendo un Metodo con compensazione di latenza che fa due cose:
1. Controlla che possiamo fare il cambiamento chiamando le callback `allow` e `deny` (questo non avviene durante la simulazione).
2. Rende effettivi i cambiamenti nel sottostante archivio dati.
### Metodi che chiamano Metodi
Se state riuscendo a seguire, potete aver notato che il nostro Metodo `post` sta chiamando un altro Metodo (`posts/insert`) quando inseriamo un nuovo post. Come funziona?
Quando la simulazione (la versione lato client del Metodo) viene eseguita, eseguiamo la simulazione di `insert` (in modo da inserire il documento nella collezione lato client), ma *non* chiamiamo la versione lato server di `insert`, perché ci aspettiamo che sia la *versione server* di `post` a farlo.
Di conseguenza quando il Metodo lato server `post` chiama `insert` non c'è bisogno di preoccuparsi della simulazione, e l'inserimento prosegue senza problemi.