Compensazione della latenza

Approfondimento 7.5

Percentuale Tradotta

In questo capitolo imparerai:

  • 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.
  • Nell'ultimo capitolo abbiamo introdotto un nuovo concetto nell'universo di Meteor: i Metodi.

    Without latency compensation
    Without latency compensation

    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

    With latency compensation
    With latency compensation

    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 è 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):

    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;
      }
    });
    
    collections/posts.js

    Nota: in caso ve lo stiate chiedendo, il this in this.isSimlation è un oggetto di invocazione di Metodo che provvede accesso a svariate e utili variabili.

    Come funziona esattamente Futures 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:

    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');
      }
    });
    
    client/views/posts/post_submit.js

    Commit 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):

    Our post as first stored in the client collection
    Our post as first stored in the client collection

    Cinque secondi più tardi, viene rimpiazzato dal domento reale che è stato inserito sul server:

    Our post once the client receives the update from the server collection
    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.