Kompensacja lagów

Pasek boczny 7.5

procent przetłumaczone

W tym rozdziale dowiesz się:

  • jak zrozumieć kompensację lagów.
  • jak zwolnić swoją aplikację i zobaczyć co dzieje się naprawdę podczas jej pracy.
  • jak metody Metora wywołują się nawzajem
  • W ostatnim rozdziale wprowadziliśmy nowy koncept w świecie Metora: Metody,

    Bez kompensacji lagów
    Bez kompensacji lagów

    Metoda w Meteorze umożliwia uruchomienie serii komand na serwerze w uporządkowany sposób. W naszym przykładzie, użytliśmy Metody ponieważ chcieliśmy upewnić się, że nowe posty zostaną otagowane imieniem autora i jego id oraz bieżącym czasem serwera.

    Gdyby jednak Meteor uruchamiał Metody w sposób najbardziej podstawowy, mielibyśmy problem. Rozważ następującą sekwencję zdarzeń (uwaga: znaczniki czasu są losowymi wartościami, wybranymi wyłącznie dla celów demonstracyjnych):

    • +0ms: Użytkownik klika na przycisk wyślij i przeglądarka wywołuje Metodę po stronie serwera.
    • +200ms: Serwer wprowadza zmiany w bazie danych Mongo
    • +500ms: Klient odbiera powyższe zmiany i uaktualnia interfejs użytkownika aby je odzwierciedlić.

    Jeżeli tak działałby Meteor, występowałby bardzo krótki lag (przerwa) między wykonywaniem powyższych akcji i zobaczeniem wyników na ekranie (opóźnienie byłoby mniej lub bardziej widoczne w zależności od odległości do serwera). Nie możemy tak funkcjonować w nowoczesnej aplikacji webowej!

    Kompensacja Lagów

    Z kompensacją lagów
    Z kompensacją lagów

    Aby obejść ten problem, Meteor wprowadza koncept Kompensacji lagów. Gdy zdefiniowaliśmy metodę posts, umieściliśmy ją w pliku znajdującym się w folderze collections/. Oznacza to, że jest dostępna zarówno dla serwera oraz klienta – oraz to, że będzie uruchomiona na obu w tym samym czasie!

    Gdy wywołujesz metodę serwerową, klient wysyła wywołanie do serwera i jednocześnie symuluje wykonanie akcji metody na kolekcjach znajdujących się u klienta. Nasza sekwencja zdarzeń wygląda teraz następująco:

    • +0ms: Użytkownik klika na przycisk wyślij i przeglądarka wywołuje metodę po stronie serwera
    • +0ms: Klient symuluje akcję wywołania metody na kolekcji klienta i zmienia UI odzwierciedlając zmiany
    • +200ms: Serwer wprowadza zmiany w bazie danych Mongo
    • +500ms: Klient otrzymuje zmiany od serwera i cofa symulowane zmiany, zmieniając je zmianami ze strony serwera (które ogólnie są takie same). UI zmienia się odzwierciedlając nowe zmiany.

    W wyniku tego użytkownik natychmiastowo widzi zmiany. Gdy odpowiedź serwera jest zwracana po kilku chwilach, może, ale nie musi być widoczna zmiana podczas transferu autentycznych dokumentów. Można się z tego nauczyć tego, że powinniśmy upewnić się, że symulujemy prawdziwe dokumenty tak bardzo jak to możliwe.

    Obserwacja kompensacji lagów

    Możemy dodać małą zmianę do wywołania metody post aby zobaczyć to w trakcie działania. Aby tego dokonać, napiszemy w pewnym sensie zaawansowaną implementację kodu używając pakietu npm futures, aby opóźnić wstawianie obiektów w ciele metody po stronie serwera.

    Sprawdzimy zmienną isSimulation aby zapytać Meteora czy metoda jest aktualnie wykonywana jako stub. Stub jest symulacją Metody, którą Meteor wykonuje równolegle po stronie klienta, podczas gdy “prawdziwa” metoda jest uruchomiona na serwerze.

    Zapytamy zatem Metora czy kod jest wykonywany po stronie klienta. W przypadku odpowiedzi twierdzącej, dodamy słowo (client) do tytułu posta. W przypadku odpowiedzi przeczącej dodamy słowo (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

    Uwaga: gdybyś się zastanawiał, this w this.isSimulation jest obiektem wywołanej metody który dostarcza dostęp do wielu przydatnych zmiennych.

    Dokładny sposób działania Futures jest poza zakresem tej książki, wspomnimy tylko, że nakazaliśmy, aby Meteor poczekał 5 sekund przed wstawieniem danych do kolekcji po stronie serwera.

    Dodamy także przekierowanie wysłania posta bezpośrednio do listy postów:

    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

    Zatwierdź 7-5-1

    Pokazanie porządku pojawiania się postów za pomocą sleep.

    Jeżeli utworzymy teraz posta, wyraźnie zobaczymy kompensację lagów w czasie działania. Na początku tytuł posta ma przyrostek (client) (pierwszy post z listy, podlinkowany do GitHub):

    Post zapisany po stronie klienta
    Post zapisany po stronie klienta

    Następnie pięć sekund później, jest on zamieniany prawdziwą zawartością dokumentu przysłaną przez serwer:

    Post po aktualizacji ze strony serwera
    Post po aktualizacji ze strony serwera

    Metody do pracy z kolekcją po stronie klienta

    Widząc to możesz pomyśleć, że metody wykonywane po stronie serwera są skomplikowane, ale tak naprawdę mogą być całkiem proste. Widzieliśmy już trzy proste motedy: metody zmiany kolekcji, insert, update i remove.

    Gdy definujesz kolekcję po stronie serwera o nazwie posts, definiujesz pośrednio trzy metody: posts/insert, posts/update i posts/delete. Innymi słowy, gdy wołasz Posts.insert() na kolekcji po stronie klienta, tworzysz metodę która jest kompensowana serwerem i która wykonuje dwie rzeczy:

    1. Sprawdza, czy można wykonać zmianę przez zawołanie callbacków allow i deny (nie jest to wykonywane w przypadku symulacji)
    2. Przeprowadza prawdziwą zmianę w bazie danych.

    Metody do pracy z kolekcją po stronie serwera

    Jeżeli nadążasz, mogłeś zdać sobie sprawę, że nasza metoda post podczas wstawiania postów wywołuje inną metodę (posts/insert). Jak to działa?

    Gdy uruchamiana jest symulacja (wersja metody po stronie klienta), wykonujemy symulację insert (zatem wprowadzamy dane do koelekcji po stronie klienta), ale nie wołamy prawdziwej metody insert po stronie serwera, ponieważ oczekujemy, że wykona to serwerowa wersja metody post.

    Co za tym idzie, gdy serwerowa metoda post woła insert, nie ma potrzeby o martwienie się o symulację i wprowadzenie danych przebiega płynnie.