Web-1/AJAX

Uit Inf2019
Naar navigatie springen Naar zoeken springen
De printervriendelijke versie wordt niet langer ondersteund en kan weergavefouten bevatten. Werk uw browserbladwijzers bij en gebruik de gewone afdrukfunctie van de browser.
Web1
Netwerken

Zie ook Regels en richtlijnen
Zie ook Artikelen bewerken

AJAX (en client-side rendering)

Wat is AJAX?

AJAX staat voor: Asynchronous JavaScript and XML. Dit is een andere oplossing voor de interactie tussen de client en de server dan we eerder gezien hebben (HTML formulieren):

  • het HTML-request wordt verstuurd vanuit JavaScript in de browser (in plaats van direct vanuit HTML); ook de response wordt vanuit JavaScript afgehandeld;
  • het versturen van dit request, en het ontvangen van de response, gebeurt asynchroon; dit wil zeggen dat de rest van de JavaScript-code in de browser niet wacht op het resultaat, en beschikbaar is voor de interactie met de gebruiker;
  • de response van de server bestaat niet uit een HTML-document, maar uit een XML-document, of tegenwoordig meestal een JSON-document. Dit bevat alleen de relevante data, in een handig formaat, en niet de "ballast" van een compleet HTML-document.

Het verwerken van de ontvangen response betekent meestal dat de DOM aangepast wordt: dit is het JavaScript-interface van het lokale HTML-document.

Hoe AJAX?

De "native" JavaScript-opdrachten die in de browser beschikbaar zijn voor interactie met de server zijn nogal complex in het gebruik. Voor ons eerste voorbeeld gebruiken we daarom de jQuery-library. We geven hier een paar voorbeelden:

$.get('/api/users', function (data) {
    users.innerHTML = data;
});

$.post('/login', $("loginform").serialize(), function (data) {
    users.innerHTML = data;
});
  • dit is JavaScript-code die uitgevoerd wordt in de client (browser);
  • $ is een identifier: een andere naam voor jQuery
  • de eerste parameter is de URL van het request;
  • bij de post bevat de tweede parameter de data van het formulier, in URL-encoded-formaat (via "serialize");
  • de response is asynchroon: daarom hebben deze opdrachten een callback-functie die uitgevoerd wordt als de response ontvangen is. In die callback-functie wordt de response-data gebruikt om de DOM bij te werken.
  • in het bovenstaande geval gaan we ervan uit dat de response-data in JSON-formaat is.
  • in de praktijk kan er veel misgaan bij de communicatie tussen de client en de server. In een serieus JavaScript-programma moet je daarmee rekening houden. Voor de eenvoud hebben we het afhandelen van fouten hier weggelaten.

AJAX test flow

AJAX test: login

De volledige flow is te vinden in: /AJAX-test-flow

Als voorbeeld van AJAX in NodeRed gebruiken we weer het login-formulier, maar nu met de AJAX-aanpak. Het formulier bevat ook de lijst met aangemelde gebruikers. Dit voorbeeld bestaat uit de volgende deel-flows:

  • get(/login): levert een HTML-document voor de login, met daarin de JavaScript-code voor de client.
  • post(/login-form): verwerkt de formulier-data, en stuurt de lijst met aangemelde gebruikers als resultaat - in JSON-formaat;
  • no-users: (via inject-node) lijst met gebruikers wordt leeg (flow.set("users", []);).

process-login:

msg.users = JSON.stringify(flow.get("users") || []);
return msg;

clientscript:

var users = document.getElementById("users");
var login = document.getElementById("loginform");

login.onsubmit= function (event) {
    event.preventDefault();
    $.post("/login-form", $("#loginform").serialize(), function (data) {
        users.innerHTML = JSON.stringify(data);
        login.username.value = "";
    });
};

Dit script wordt meegestuurd in het HTML-bestand; het wordt uitgevoerd in de browser.

  • de aanroep event.preventDefault(); is om te voorkomen dat de browser het formulier alsnog opstuurt (volgens de regels voor HTML-formulieren).
  • na het opsturen van de username moet het invoerveld weer leeg gemaakt worden; dat moeten we in het programma expliciet doen.

Page-template:

<!doctype html>
<html>
  <head>
      <title>Login</title>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
  </head>
  <body>
    <h3>Login</h3>
    <form id="loginform">
      Your name:
      <input type="text" name="username">
      <button type="submit">Submit</button>
    </form>
    <div>
        active users:
        <div id="users">{{users}}</div>
    </div>
    <script>
        {{{clientscript}}}
    </script>
  </body>
</html>

Process-login-form:

var username = msg.payload.username || "";
var users = flow.get("users") || [];
if (!users.includes(username) && (username !== "")) {
    users.push(username);
}
flow.set("users", users);
msg.user = username;
msg.cookies = {user: username};
return msg;

get-users:

msg.payload = flow.get("users") || [];
return msg;

Opdrachten

  • bouw deze flow (of kopieer deze van /AJAX-test-flow);
  • controleer de werking via de browser (zo mogelijk via meerdere browsers);
  • bekijk de requests en responses in de ontwikkeltools in de browser;
    • hoe herken je hierin de AJAX-interactie? Wat zijn de verschillen met een HTML-interactie?
  • bekijk de requests in de server (voor de post);
    • voeg hiervoor aan de output van de post een debug-node toe, voor de complete msg;
  • wat gebeurt er als je in het client-script de event.preventDefault();weglaat?
    • vergeet niet dit veranderde script te laden, door de pagina in de browser te verversen.

Polling: up to date houden van de lijst van gebruikers

Polling met AJAX

De flow-code is te vinden op /AJAX-polling.

De lijst van aangemelde gebruikers hangt af van de gebruikers die zich aanmelden bij de server. Deze lijst kan veranderen zonder actie van de huidige gebruiker. Om toch een actuele lijst te kunnen laten zien voegen we een functie toe die regelmatig (elke minuut) deze lijst ophaalt bij de server. Dit "regelmatig opvragen of er nieuwe data is" heet ook wel "polling".

  • get(/api/users): stuurt de lijst met aangemelde gebruikers (zie vorige voorbeeld);
  • we voegen de polling-code toe aan het client-script. De functie getUsers wordt elke 60 sec. uitgevoerd (via een timer); deze stuurt een get-request naar de server, en verwerkt de resulterende lijst met gebruikers in de huidige pagina.

clientscript (uitgebreid met getUsers):

var users = document.getElementById("users");
var login = document.getElementById("loginform");

login.onsubmit= function (event) {
    event.preventDefault();
    $.post("/login-form", $("#loginform").serialize(), function (data) {
        users.innerHTML = JSON.stringify(data);
        login.username.value = "";
    });
};

function getUsers() {
  $.get("api/users", function (data) {
      users.innerHTML = JSON.stringify(data);
  });
}

getUsers();

window.setInterval(getUsers, 60000); // timer in msec

Opdrachten

  • breid de vorige flow uit tot deze flow;
  • controleer de werking van deze flow, via de browser;
    • verander eerst de time-out in een kleinere waarde (bijv. 15 seconden);
    • open deze flow in meerdere browsers: een wijziging via de ene browser moet dan na enige tijd in de andere browser te zien zijn, zonder dat je de pagina ververst;
  • bekijk in de ontwikkeltools van de browser (Netwerk-tab) de requests en responses.

Meer over AJAX

Waarom AJAX?

Bij een gedistribueerd systeem speelt altijd de vraag hoe het rekenwerk verdeeld moet worden over de verschillende agents. Ook moet je bepalen waar welke data opgeslagen wordt. Bij het web, als client-server systeem, was de oorspronkelijke verdeling helder: het rekenwerk -met als resultaat een html-document- vindt plaats op de server; de browser hoeft dan alleen te bepalen hoe dit document weergegeven kan worden op het scherm. Maar de komst van JavaScript, met krachtiger computers aan de kant van de browser, maakt andere oplossingen mogelijk. Een deel van de constructie van het html-document kan in de client plaatsvinden, met behulp van client-side scripting (JavaScript).

JavaScript wordt zowel gebruikt voor de interactie met de gebruiker, als voor de interactie met de server. Deze server-interactie gebeurt gewoonlijk asynchroon: dat wil zeggen dat het JavaScript-programma doorgaat terwijl een verzoek naar de server onderweg is. De gebruiker kan dan verdere interactie plegen met het programma, en hoeft niet te wachten totdat de server-response binnenkomt. Een website met JavaScript kan dan voor de gebruiker veel sneller zijn dan een puur-html website.

Wat zijn enkele van de voor- en nadelen van deze alternatieven?

client-side scripting server-side scripting
snelle interactie met gebruiker trage interactie met gebruiker
alleen (compacte) data in communicatie met server communicatie met client als complete HTML-documenten
templates in client templates in server
sterk variërende omgeving (allerlei browsers) één omgeving (server)

Voor de server is er in eerste instantie geen (groot) verschil tussen een AJAX-request en een normaal httop-request van de browser: hierbij worden dezelfde ingrediënten gebruikt (method; URL; parameters; enz.). Het belangrijkste verschil is dat het resultaat geen HTML-document hoeft te zijn. Dit kan de verwerking in de server vaak veel eenvoudiger maken.

Enkele van de moderne browser-libraries (zoals Elm, Vue, ...) zijn erg efficient in het bepalen welk deel van de html-rendering gelijk kan blijven, en welk deel aangepast moet worden. Dit betekent dat bij een kleine verandering van de dynamische data, er ook maar een klein deel van het scherm opnieuw getekend hoeft te worden: dat resulteert in een veel soepeler weergave van de website.


/AJAX-experimenten