forked from DiscoverMeteor/DiscoverMeteor_fr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
07s-latency-compensation.md.erb
136 lines (96 loc) · 7.99 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
134
135
136
---
title: La Compensation de Latence
slug: latency-compensation
date: 0007/01/02
number: 7.5
points: 5
sidebar: true
photoUrl: http://www.flickr.com/photos/ikewinski/9473352049/
photoAuthor: Mike Lewinski
contents: Comprendre la compensation de latence.|Ralentissez votre application et voyez ce qu'il se passe.|Apprendre comment les méthodes Meteor interagissent entre elles.
paragraphs: 28
---
Dans le dernier chapitre, nous avons présenté un nouveau concept du monde Meteor : les **Méthodes**.
<%= diagram "latency1", "Sans compensation de latence", "pull-right" %>
Une Méthode Meteor est un moyen d'exécuter une série de commandes sur le serveur d'une façon structurée. Dans notre exemple, nous avons utilisé une Méthode car nous voulions nous assurer que les nouveaux articles seraient tagués avec le nom et l'id de leur auteur ainsi que l'heure du serveur.
Cependant, si Meteor exécute des Methodes dans sa plus simple façon, nous aurions un problème. Considérez la séquence suivante d'évènements (note : les horodatages sont des valeurs aléatoires choisies seulement pour l'exemple) :
- *+0ms:* L'utilisateur clique sur un bouton et le navigateur renvoie un appel de Méthode.
- *+200ms:* Le serveur fait des changements dans la base de données Mongo
- *+500ms:* Le client reçoit ces changements, met à jour l'interface utilisateur.
Si ceci était la façon dont Meteor opèrait, alors il y aurait un petit décalage entre effectuer de telles actions et en voir les résultats (ce décalage étant plus ou moins visible selon votre proximité avec le serveur). Nous ne pouvons nous permettre ça dans une application web moderne !
### Compensation de latence
<%= diagram "latency2", "Avec compensation de latence", "pull-right" %>
Pour éviter ce problème, Meteor introduit un concept appelé **Compensation de latence**. Quand nous avons définit notre Méthode `post`, nous l'avons plaçé à l'intérieur d'un fichier dans le répertoire `collections/`. Ceci signifie qu'elle est disponible pour le serveur *et le client* -- et elle s'exécutera sur les deux en même temps !
Quand nous faisons un appel de Méthode, le client envoie l'appel au serveur, mais *simule* également simultanément l'action de la Méthode sur ses collections côté client. Notre workflow devient :
- *+0ms:* L'utilisateur clique sur un bouton et le navigateur renvoie un appel de Méthode.
- *+0ms:* Le client simule l'action de l'appel de Méthode sur les collections côté client et met à jour l'interface utilisateur pour refléter ceci.
- *+200ms:* Le serveur fait les changements dans la base de données Mongo.
- *+500ms:* Le client reçoit ces changements et annule ses changements simulés, en les remplaçant par les changements du serveur (qui sont généralement les mêmes). L'interface utilisateur change pour refléter ceci.
Le résultat pour l'utilisateur est de voir les changements instantanément. Quand la réponse du serveur revient un peu plus tard, il peut y avoir (ou non) des changements visibles à mesure que les documents canoniques du serveur arrivent. Une chose à retenir est donc que nous devons nous assurer que nous simulons les documents aussi proches de la réalité que possible.
### Observer une compensation de latence
Nous pouvons faire un petit changement à l'appel de Méthode `post` pour voir cela en action. Pour ce faire, nous développerons du code avancé avec le paquet npm `futures` pour retarder l'insertion d'objets dans notre méthode.
Nous utiliserons `isSimulation` pour demander à Meteor si la Méthode actuellement invoquée est une ébauche. Une [ébauche](http://docs.meteor.com/#methods_header) est la simulation d'une Méthode que Meteor exécute sur le client en parallèle, pendant que la "vraie" Méthode est en cours d'exécution sur le serveur.
Nous allons donc demander à Meteor si le code est en cours d'exécution sur le client. Si c'est le cas, nous allons ajouter la chaîne de caractère `(client)` à la fin du titre de notre article. Sinon, nous ajouterons la chaîne de caractère `(server)` :
~~~js
Meteor.methods({
post: function(postAttributes) {
// […]
// récupérer les clés de la liste blanche
var post = _.extend(_.pick(postAttributes, 'url', 'message'), {
title: postAttributes.title + (this.isSimulation ? '(client)' : '(server)'),
userId: user._id,
author: user.username,
submitted: new Date().getTime()
});
// Attendre 5 secondes
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" %>
Note : Au cas où vous vous le demandez, le `this` dans `this.isSimulation` est un [objet d'invocation de Méthode](http://docs.meteor.com/#meteor_methods) qui fournit un accès à diverses variables utiles.
Comment fonctionnent exactement les [Futures](https://npmjs.org/package/future) est hors du cadre de ce livre, mais nous avons simplement dit à Meteor d'attendre 5 secondes avant de faire l'insertion dans la collection côté serveur.
Nous allons faire une redirection d'envoi directement vers la liste d'articles :
~~~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", "Démontrer l'ordre d'apparition des articles en utilisant un sleep." %>
Si nous créons un article maintenant, nous voyons clairement la compensation de latence en action. Premièrement, un article est inséré avec `(client)` dans le titre (le premier article dans la liste, relié à Github) :
<%= screenshot "s5-1", "Notre article comme initialement stocké dans la collection côté client" %>
Ensuite, cinq secondes plus tard, il est proprement remplacé avec le vrai document qui a été inséré par le serveur :
<%= screenshot "s5-2", "Notre article une fois que le client reçoit la mise à jour de la collection côté serveur" %>
### Méthodes des collections sur le client
Vous pourriez penser que les Méthodes sont compliquées après cela, mais en fait elles peuvent être plutôt simples. En fait, nous avons déjà vu trois méthodes très simples : les Méthodes de mutation de collection, `insert`, `update` et `remove`.
Quand vous définissez une collection serveur appelée `'posts'`, vous êtes implicitement en train de définir trois Méthodes : `posts/insert`, `posts/update` et `posts/delete`. En d'autres mots, quand vous appelez `Posts.insert()` sur votre collection client, vous appelez une Méthode de compensation de latence qui fait deux choses :
1. Des vérifications pour voir si vous faites la mutation en appelant des callbacks `allow` et `deny` (cependant il n'est pas nécessaire que cela arrive dans la simulation).
2. La modification vers le stockage de données sous-jacent.
### Des méthodes qui appellent des Méthodes
Si vous suivez bien, vous venez peut-être juste de réaliser que notre Méthode `post` appelle une autre Méthode (`posts/insert`) quand nous insérons notre article. Comment ça marche ?
Quand la simulation (version côté client de la Méthode) est en cours d'exécution, nous effectuons la simulation d'un `insert` (nous insérons donc dans notre collection cliente), mais nous *ne* faisons *pas* le vrai, `insert` côté serveur, nous attendons que la version *côté serveur* de `post` le fasse.
Par conséquent, quand la Méthode `post` côté serveur appelle `insert` il n'y a pas besoin de s'inquiéter de la simulation, et l'insertion continue sans encombre.