Pour votre progression, c'est très important de finir le sujet précédent avant de commencer celui-ci.
Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.
Où seront normalement effectuées ces opérations ou déclarations?
SELECT * FROM users WHERE id=123
document.addEventListener
p {
color: red;
}
$f=file_get_contents('fichier.txt');
<img alt="photo" src="photo.jpg" />
Formulaire permettant de payer en ligne
Clique sur un bouton pour afficher les 10 commentaire suivants
Effectuer une recherche dans un moteur de recherche
Ajouter un commentaire dans un forum
Effacer un commentaire dans un forum
Vous faites du développement « frontend ».
Sur quel logiciel s’exécute votre code généralement ?
On a déjà le code suivant:
let prix=123;
let parfum='Chocolat';
let nom='Tom';
Réécrivez ce code en raccourcissant si possible:
let commande={ prix: prix, parfum: parfum, client: nom };
Vous êtes sur la bonne voie.
Indice: Quand peut-on raccourcir ?
...
<body>
<script>
console.log('A');
document.addEventListener('click',()=>console.log('C'));
console.log('B');
</script>
</body>
...
Où est-ce que le navigateur passe son temps entre console.log('B') et console.log('C') ?
Oui, dans la boucle d'événements.
Oui, il y a bien « boucle ». Il manque quelque-chose.
Que verra l'utilisateur ?
<script>
document.body.style.backgroundColor='red';
document.body.style.backgroundColor='green';
document.body.style.backgroundColor='blue';
</script>
Une page bleue
En effet, après que ce <script> soit fini, le navigateur finit de traiter la page HTML, puis il va dans la boucle d'événements puis dans la partie affichage.
Ce n'est qu'alors que la page est affichée.
Une page rouge
Une page verte
Successivement un changement de couleur:
d'abord rouge, puis vert, puis bleu
On veut animer une image pour qu'elle défile progressivement de gauche à droite.
Est-ce que ce code marche ?
...
<script>
let image=document.querySelector('img');
for(let i=0;i<500;i++){
image.style.left=i+'px';
}
</script>
...
Non
En effet. Comme pour la question précédente. L'affichage ne se fera qu'après la fin du script. Quand le navigateur sera retourné dans la boucle d'événements, puis dans la partie affichage.
L'utilisateur ne verra donc que l'image à droite.
Oui
...
<script>
document.addEventListener('click',()=>{console.log('bonjour')});
</script>
...
L'utilisateur clique 10 fois sur la page. Combien de fois est-ce que addEventListener est appelé ?
En effet, addEventListener ne fait qu'enregistrer la fonction anonyme sur le document. Ceci se fait une seule fois, quand <script> est exécuté au chargement de la page.
Plus tard, chaque fois que l'utilisateur clique, le navigateur appelle la fonction anonyme.
La fonction attendre renvoie une promesse qui est toujours tenue après une durée de 1000ms
<script>
console.log('A');
let p1=attendre();
let p2=attendre();
let p3=attendre();
console.log('B');
</script>
Combien de temps s'écoule entre console.log('A') et console.log('B') ?
Moins de 10 ms
Autour de 3000 ms
Autour de 1000 ms
Autant qu'il faut, mais pas plus.
Hum. Oui, mais précisez un peu. ;-)
La fonction attendre() renvoie une promesse qui est toujours tenue après une durée de 1000ms
<script>
console.log('A');
attendre().then(()=>console.log('ok1'));
attendre().then(()=>console.log('ok2'));
attendre().then(()=>console.log('ok3'));
console.log('B');
</script>
Combien de temps s'écoule entre console.log('A') et console.log('ok3') ?
autour de 1000 ms
En effet, les 3 fonctions attendre sont appelées au chargement de la page, presque au même moment.
Moins de 10ms
autour de 2000 ms
autour de 3000 ms
Node.js est un environnement permettant d’exécuter du JS en-dehors du navigateur.
Il peut-être utilisé coté serveur, mais il peut aussi être utilisé dans d'autres contextes, comme la plupart des langages de programmation.
Node.js n’étant pas dans le navigateur, on ne peut pas accéder au DOM.
Par contre, on peut accéder aux fonctionnalités du système, qui ne sont pas disponibles dans le navigateur (pour des raisons de sécurité).
On peut lire et écrire des fichiers, on peut créer des serveurs, on peut créer des processus, on peut accéder à une base de données, etc.
Quelles affirmations sont vraies ?
A partir de Node.js, on peut lire un fichier
Dans le navigateur, on peut se connecter sur une base de données MySQL
En Node.js, on peut écrire:
document.body.style.backgroundColor='red';
En Node.js je peux créer un processus pour exécuter un programme comme « ls » qui affiche le contenu d'un répertoire.
Node JS s’exécute dans le navigateur
Ouvrez un terminal.
Tapez:$ node
Vous êtes dans une console, similaire à celle du navigateur!
Essayez des instructions, comme « 1+1 » ou « console.log('Bonjour') »
Créez un fichier hello.js
Dans ce fichier écrivez :
console.log('Hello world');
Dans le terminal, executez-le:
$ node hello.js
Pour pouvoir utiliser des fonctionnalités fournies par différentes librairies, il faut d'abord aller les chercher.
Vous l'avez vu dans d'autres langages: « import » dans python et Java, « include » ou « require » en PHP. «include » en C.
Node.js propose deux manières de le faire:
import * as fs from 'node:fs/promises';
import * as fs from 'node:fs/promises';Remarquez que readFile retourne une promesse. On utilise « await »
const pass=await fs.readFile('/etc/passwd','utf8');
import * as fs from 'node:fs/promises';
import
*
fs (le premier)
from
node:
fs (le 2e)
/promises
Dans Node.js on va utiliser une approche « asynchrone », comme dans le navigateur.
C'est à dire, qu'on ne doit pas bloquer l’exécution du JS.
Toutes les opérations qui prennent du temps (lire un fichier, faire une requête à une base de données, attendre une connexion réseau...), doivent se faire en deux temps:
Souvent, on peut utiliser des promesses.
Dans ce cas, on peut utiliser async/await pour éviter d'utiliser un callback:
console.log('avant');
const pass=await fs.readFile('/etc/passwd','utf8');
console.log('après');
...
Sans « await », on aurait du écrire:
console.log('avant');(Remarque: il est possible en Node.js de faire du code qui n'est pas asynchrone, en utilisant des versions bloquantes de fonctions comme readFile. Cette approche est moins utilisée et elle est incompatible avec les logiciels qu'on verra ici: Express, Vue.js ...)
fs.readFile('/etc/passwd','utf8').then(pass=>{
console.log('après');
...
});
Dans l'exemple précédent on a utilisé la librairie 'fs', qui est intégrée à Node.js
En général, on veut aussi utiliser d'autres librairies.
npm est à la fois une commande permettant de gérer des paquets et un répertoire en ligne de paquets qu'on peut installer.
Ce répertoire « npm » fournit plus d'un million de paquets.
Chacun peut y publier ses propres paquets.
Généralement, pour utiliser npm, vous devez mettre votre logiciel dans un répertoire à lui.
La commande npm s’utilise alors dans ce répertoire.
Elle utilise un fichier « package.json » qui décrit votre logiciel et ses dépendances.
Les dépendances sont les paquets ("librairies") dont votre logiciel a besoin pour fonctionner.
npm fournit de nombreuses sous-commandes. En voici deux:
Quelles affirmations sont vraies ?
Les paquets téléchargés par npm peuvent être très nombreux et volumineux
« npm init » crée un fichier appelé package.json
« npm init » télécharge des paquets
Non, c'est « npm install » qui télécharge les paquets
les paquets téléchargés par npm sont mis dans un répertoire appelé « packages »
Non, ils sont mis dans « node_modules »
Quand vous installez un paquet, un seul paquet est téléchargé
Non, en général le paquet a des dépendances. Elles sont téléchargées aussi.
Vous n'avez pas besoin de modifier à la main le fichier package-lock.json
Pour utiliser npm, on doit mettre son logiciel dans un répertoire qui lui est propre.
On va créer un petit serveur web avec une librairie appelée « express ».
Créez un répertoire « monserveur » et rentrez dedans.
Quelle commande faut-il taper pour créer package.json ?
Tapez « npm init » et répondez aux questions (vous pouvez appuyer sur entrée sur toutes).
Regardez le fichier package.json crée.
Quels champs voyez vous dedans ?
author
scripts
dependencies
files
config
version
A part package.json, combien d'autres fichiers ou répertoires voyez vous dans le répertoire de votre logiciel ?
(tapez un nombre)
Quelle commande faut-il taper ?
Non. « npm init » sert à initialiser (démarrer) un nouveau projet.
Ici, votre projet est déjà crée. On veut ajouter un la possibilité d'utiliser le paquet « express »
Vous êtes sur la bonne voie. Ca commence bien par « npm install »
Tapez « npm install express ».
Laissez la commande le temps de s’exécuter.
npm télécharge le paquet express et ses dépendances.
Un nouveau répertoire est crée. Comment s'appelle-t-il ?
Allez dans node_modules.
Chaque répertoire est un paquet désarchivé.
Il s'agit de « express » et de toutes ses dépendances.
Quels répertoires voyez vous ?
express
etag
apache
mime
methods
babel
Allez dans le répertoire « express ».
Vous devriez trouver un fichier « package.json ».
En effet, chacun des paquets est un logiciel npm comme le votre. Il a son propre fichier « package.json »
Lisez le fichier package.json d'express.
Comment s’appelle l'auteur du paquet « express » ?
Lisez le fichier package.json d'express.
On a vu, à une question précédente, que « express » utilisait des paquets comme « mime », « etags », « methods », ...
Essayez de trouver ces noms dans ce package.json.
Comment s'appelle le champs de ce fichier package.json qui liste tous ces paquets ?
Le champs « dependencies » est un objet JSON qui liste tous les noms de paquets dont le paquet dépend, avec des indications sur les numéros de version.
Remontez dans le répertoire de votre logiciel (monserveur).
Lisez votre fichier package.json
Quel est le nom du paquet dans "dependencies" ?
En effet « express » a été ajouté à la liste des paquets dont dépend votre logiciel.
Quelle commande que vous avez déjà tapé a ajouté « express » à votre package.json ?
Presque. « npm install » tout seul ne fait rien.
On voudrait utiliser « import ». On a donc besoin d'utiliser un module js.
On a vu qu'on pouvait utiliser l'extension de nom de fichier « .mjs ».
Une autre solution est d'utiliser un fichier « .js » et d'ajouter
"type": "module"
dans le fichier package.json (attention à bien ajuster les virgules! Le JSON a une syntaxe très stricte)
Quand node exécutera notre fichier « .js », il regardera dans package.json et saura qu'il s'agit d'un module.
Ajoutez la ligne dans package.json
On a fini la mise en place:
Express et PHP ont des architectures très différentes.
Pour utiliser PHP un logiciel appelé « serveur web » est nécessaire (Apache, NGINX).
Il reçoit les requêtes provenant des navigateurs (http://.../ex1.php, http://.../ex2.php,...)
Il trouve les fichiers PHP correspondants
Il exécute chacune de ces requêtes PHP dans un processus différent
Chaque processus peut durer longtemps (quelques centaines de ms): chaque processus peut s’arrêter en attendant une opération longue (le contenu d'un fichier, le résultat d'une base de données, etc). Le développeur PHP n'a pas besoin de s'occuper de ces attentes. C'est géré automatiquement par le fait qu'il y ait plusieurs processus.
Dans Express, il n'y a pas de serveur séparé. Il n'y a qu'un seul processus. Votre programme (app.js) est le serveur.
Les requêtes sont traitées les unes après les autres. Comme le code JS doit être non-bloquant, chaque requête est traitée très rapidement puis rend la main à la boucle d'événements.
S'il y a une opération longue à gérer, le développeur doit utiliser une des techniques de programmation asynchrone (callback, Promise, await).
C'est un problème de performance.
Lancer des processus (ou même réutiliser des processus existants) c'est long.
L'architecture JS est plus rapide. Il n'y a pas de processus à lancer. Le prix à payer est la programmation asynchrone, qui est plus compliquée... même si « await » simplifie beaucoup les choses.
Quelles affirmations sont vraies ?
Pour utiliser PHP on a besoin d'un serveur web
Pour utiliser Express on a besoin d'un serveur web
En PHP, on peut bloquer l’exécution en attendant le résultat d'une requête à la base de données.
En PHP, on utilise une boucle d'événements
Non, la boucle d'événements c’est en JS (Express)
En Express, les requêtes sont traitées successivement, les unes après les autres
En PHP, les requêtes sont exécutées en parallele
Ouf... beaucoup de théorie... passons express-ément à la pratique !
Dans monserveur, créez le fichier app.js suivant:
import express from 'express';
const app = express();
app.listen(3000, () => {
console.log('Notre app express écoute sur le port 3000')
});
app.get('/', (requete, reponse) => {
console.log('Requete GET / reçue');
reponse.send('Hello World!')
})
Démarrez le serveur avec:
$ node app.js
Vous devriez voir sur la console:
« Notre app express écoute sur le port 3000 »
Connectez vous, avec votre navigateur sur http://localhost:3000
Vous devriez voir « Hello world ! »
Ça y est, on a notre premier serveur web en Express.js !
Attention: chaque fois que vous modifiez votre JS, il faut arrêter app.js (Ctrl+C) puis relancer (node app.js)
import express from 'express';
const app = express();
app.listen(3000, () => {
console.log('Notre app express écoute sur le port 3000')
});
app.get('/', (requete, reponse) => {
console.log('Requete GET / reçue');
reponse.send('Hello World!')
})
app.get('/bonjour', (requete, reponse) => {Ceci dit à Express:
console.log('Requete GET /bonjour reçue');
reponse.send('Bonjour à toi!')
})
Ajoutez un nouvel appel à app.get qui affiche toute une page HTML complète avec l'image suivante:
https://moodle.iutv.univ-paris13.fr/img/bjs2/chat2.svg
lorsque l'utilisateur se connecte avec l'URL http://localhost:3000/miaou
Vous pouvez utiliser les « ` ... ` » ( backticks = accent grave ) à la place de « ' ... ' » ou « " ... " » pour créer une chaine de caractères sur plusieurs lignes.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
app.get('/miaou', async (requete, reponse) => {
console.log('Requete GET /miaou reçue');
reponse.send(`<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Miaou</title>
</head>
<body>
<h1>Miaou</h1>
<img src="https://moodle.iutv.univ-paris13.fr/img/bjs2/chat2.svg"/>
</body>
</html>`);
})
$ npm install
Dans monserveur, on avait affiché une page HTML en l'incluant dans le app.js avec des backticks « ` ... ` ».
Ce n'est pas très pratique.
Express permet d'indiquer un répertoire qui fournira des pages « statiques ».
C'est à dire des fichiers (HTML, CSS, JS, images, ...) qui seront envoyés directement au navigateur.
Après « const app = express(); », ajoutez:
app.use(express.static('public'));
Créez un répertoire appelé « public » dans « profils ».
Désormais, les fichiers dans « public » seront envoyés par Express directement au navigateur.
C'est similaire à un serveur web classique.
Créez un fichier « essai.html » dans public.
Vérifiez que vous pouvez y accéder par http://localhost:3000/essai.html
Créez les fichiers suivants dans public
index.html:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Profils</title>
<script src="https://moodle.iutv.univ-paris13.fr/img/bjs2/bjs2-js-lib.js"></script>
<link rel="stylesheet" href="profils.css"/>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>
<ul id="liste">
<li data-id="p125">L. Neige</li>
<li data-id="p112">Père N.</li>
<li data-id="p132">Minou</li>
<li data-id="p241">Anonyme</li>
</ul>
<div id="profil-principal" class="profil">
<img class="portrait" src="" alt=""/>
<p class="nom"></p>
<p class="stats"><span class="messages">? messages</span> <span class="likes">? likes</span></p>
<p class="description"></p>
</div>
<script type="module" src="profils.js"></script>
</body>
</html>
profils.css:
/* inspiré de https://freefrontend.com/css-profile-cards/ */
@import url("https://fonts.googleapis.com/css2?family=Baloo+Paaji+2:wght@400;500&display=swap");
body{
background: linear-gradient(45deg, rgba(255,255,255,1) 0%, rgba(240,180,149,1) 100%);
background-repeat: no-repeat;
font-family: sans;
color: #444;
background-attachment: fixed;
}
#profil-principal{
margin-left: 7em;
}
.profil {
background-color: #222831;
color: white;
width: 17em;
text-align: center;
border-radius: 5px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
font-family: 'Baloo Paaji 2', cursive;
padding: .5em;
}
.profil .portrait {
border-radius: 50%;
width: 160px;
height: 160px;
border: 5px solid #272133;
margin-top: 20px;
box-shadow: 0 10px 50px rgba(235, 25, 110, .6);
background-color: white;
}
.profil .portrait.homme {
box-shadow: 0 10px 50px rgba(25, 110, 235, .8);
}
.profil .stats {
font-size: 1.2em;
margin-top: .5em;
}
.profil .stats span {
margin: 1em;
}
.profil .nom{
margin-top: 15px;
margin-bottom: .5em;
font-size: 1.5em;
}
#liste{
display: flex;
list-style-type: none ;
}
#liste li{
margin: 1em;
background-color: #222831;
color: white;
padding: .7em;
border-radius: .3em;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.4);
cursor: pointer;
}
#liste li:hover{
background-color: #522831;
}
profils.js
// vide pour l'instant
On a besoin de données pour notre application.
Dans le répertoire principal (profils), créez le fichier profils.json:
{
"p132": {"id": "p132", "nom": "Minou", "sexe": "homme", "portrait": "https://moodle.iutv.univ-paris13.fr/img/bjs2/chat2.svg", "messages": 54, "description": "Miaou ? ", "likes": 132 },
"p125": {"id": "p125", "nom": "L. Neige", "sexe": "femme", "portrait": "https://moodle.iutv.univ-paris13.fr/img/bjs2/reindeer.png", "messages": 172, "description": "Je suis un peu timide.", "likes": 232 },
"p241": {"id": "p241", "nom": "Anonyme", "sexe": "femme", "portrait": "https://moodle.iutv.univ-paris13.fr/img/bjs2/et-masque.png", "messages": 2, "description": "J'ai beaucoup voyagé. Je cherche quelqu'un qui accepte les différences.", "likes": 5 },
"p112": {"id": "p112", "nom": "Père N.", "sexe": "homme", "portrait": "https://moodle.iutv.univ-paris13.fr/img/bjs2/santa.png", "messages": 1300482832, "description": "J'aime la nature et les paysages nordiques. Frileuses s'abstenir. Voyage d'affaires en période de fêtes.", "likes": 5103003013 }
}
Ouvrez http://localhost:3000/
Vous devriez voir une page avec 4 noms: L.Neige, Père N., Minou, Anonyme, comme ceci:
Le but dans cette partie sera d'afficher le profil de chacun dans la boite en bas, quand l'utilisateur clique sur son nom, à l'aide de requêtes AJAX.
On va faire ça ensemble dans les pages suivantes.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
app.get('/profil/p132', async (requete, reponse) => {
console.log('Requête /profil/p132 reçue');
reponse.send('bonjour');
})
Dans cette route, on veut lire le fichier profils.json pour ensuite y chercher le profil p132
Comment s’appelle la fonction Node.js permettant de lire un fichier ?
Oui, c'est fs.readFIle
Presque! Vérifiez l'orthographe
Quand vous visitez l'URL http://localhost:3000/profil/p132
lisez le fichier profils.json et affichez-le dans la console du serveur (terminal).
Indications:
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
app.get('/profil/p132', async (requete, reponse) => {
console.log('Requete /profil/p132 reçue');
let profilsTexte=await fs.readFile('profils.json','utf8');
console.log('sortie:',profilsTexte);
reponse.send('bonjour');
})
On a désormais tout le fichier profils.json dans une chaîne de caractères.
Pour l'utiliser, on a besoin de transformer cette chaîne de caractères en un objet JS.
Pour ça, on utilise la fonction JSON.parse() :
let profils=JSON.parse(profilsTexte);
Maintenant, on a bien un objet dans « profils ».
Regardez le contenu de profils.json
Que faut-il écrire pour chercher le profil p132 dans l'objet « profils »?
(sans le mettre dans une variable, ni l'afficher)
C'est vrai, on peut écrire profils.p132
Mais pour la suite on aura besoin de la notation utilisant des crochets.
Presque! Il vérifiez la syntaxe.
Vous avez écrit « console.log ». Ici, on ne veut pas l'afficher dans la console.
Ne mettez pas de « ; » à la fin.
Complétez le code pour renvoyer au navigateur le profil p132
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
app.get('/profil/:id', async (requete, reponse) => {
console.log('Requete /profil/p132 reçue');
let profilsTexte=await fs.readFile('profils.json','utf8');
let profils=JSON.parse(profilsTexte);
reponse.send(profils['p132']);
})
Notre code fonctionne pour le profil p132 uniquement.
Élargissons pour qu'il fonctionne pour tous les profils !
Express permet de créer des paramètres dans les chemins avec des « : »
app.get('/profil/:id', async (requete, reponse) => {
Ici on l'a appelé « id » (mais vous pouvez l'appeler comme vous voulez).
Dans la fonction, on récupère sa valeur dans « requete.params.id »
Donc pour l'URL http://localhost/profil/xyz on récupérera 'xyz' dans « requete.params.id »
Utilisez ceci pour que votre code fonctionne pour tous les profils.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
app.get('/profil/:id', async (requete, reponse) => {
console.log('Requete GET /profil reçue');
let id=requete.params.id;
let profilsTexte=await fs.readFile('profils.json','utf8');
let profils=JSON.parse(profilsTexte);
reponse.send(profils[id]);
})