Vilka steg för att komma igång
- Installera node.js och npm
- Installera en editor (ex. Visual Studio Code)
- Installera en terminal (ex. Git Bash, Windows Terminal)
- Installera en webbläsare (ex. Chrome, Firefox)
- command: npm init -y (skapa en package.json fil)
- Installera moduler som behövs (ex. body-parser, cors, underscore, dotenv)
- Det finns vissa moduler inbyggd som ex. http, fs, path, url, os, events, stream, util, querystring
- command: npm i express (installera express)
// Importera express
const express = require("express");
var cookieParser = require('cookie-parser');
// Skapa en express app
const app = express();
// Använda moduler
app.use(cookieParser());
- command: npm i nodemon (installera nodemon för att köra servern automatiskt efter ändringar)
- command: nodemon index.js (starta servern)
Node.js
Node.js är en JavaScript runtime byggd på Chrome V8 motorn. Det kör JavaScript kod på server-sida. Det är non-blocking, asynkron-arkitektur och körs på singel threaded. Det kan ha tillgång till filer och operativsystem datavaser som kan inte göras i webbläsaren. Det håller koll på sessions och cookies.
Moduler
Att använda moduler importera och exportera funktioner och variabler mellan olika filer. Det är ett sätt att organisera koden och göra den mer läsbar och underhållbar.
// Importera moduler
const express = require("express");
const fs = require("fs");
const path = require("path");
//...
Routrar
Routrar används is den kontext som vi lärde att dela upp funktionalitet för olika URL endpoints. (ex. localhost:xxxx/api/hello_world, /, /wow ect).
Att komma igång behövs det express.
// index.js
// Importera express modul
const express = require("express");
// Importera routrar
const helloWorldRouter = require("./routes/hello_world");
// Skapa en express app
const app = express();
// Använda routrar (localhost:xxxx/api/hello_world)
app.use("/api/hello_world", helloWorldRouter);
Router fil ligger i en mapp kallad routers och filen själv heter hello_world.js.
// hello_world.js
// Importera express modul
const express = require("express");
// Skapa router
const router = express.Router();
// Skapa en endpoint för /api/hello_world
// Request och response objekt är inbyggda i express och används för att hantera inkommande request och skicka svar tillbaka till klienten.
router.get("/", (req, res) => {
res.send("Hello World!");
});
// Exportera routern så index.js kan använda den router
module.exports = router;
HTTP metoder
Det finns olika HTTP metoder som används för att skicka och ta emot data mellan klient och server. De vanligaste metoderna är:
- GET: Används för att hämta data från servern (För att visa på webbläsaren). Exempel:
router.get("/api/hello_world", (req, res) => {...})
- POST: Används för att skicka data till servern. Exempel:
router.post("/api/hello_world", (req, res) => {...})
- PUT: Används för att uppdatera data på servern. Exempel:
router.put("/api/hello_world", (req, res) => {...})
- DELETE: Används för att ta bort data från servern. Exempel:
router.delete("/api/hello_world", (req, res) => {...})
Masterframe konsept
Iställe för att ha en stor statisk HTML dokument man kan ha mindre delar som kombineras i en router. Det är bra att omanvända delar och ha lättare vis att ändra delar över hela sidan. Man kan ha alla HTML delar i en mapp kallad masterframe. Vi kan laga en funktion i en module som returnerar html filen
// readHTML.js
var fs = require('fs');
function readHTML(htmlfile) {
try {
htmltext = fs.readFileSync(htmlfile, 'utf8');
} catch (err) {
console.error(err);
}
return htmltext;
}
module.exports = readHTML;
// Exempel på en router där det används masterframe
const express = require("express");
const router = express.Router();
const fs = require("fs");
var path = require("path");
const readHTML = require('./readHTML');
var htmlPart = readHTML('./masterframe/hello_world.html');
var htmlPart2 = readHTML('./masterframe/hello_world2.html');
router.get("/", (req, res) => {
res.write(htmlPart);
res.write("<p>Hello World!</p>");
res.write(htmlPart2);
res.end();
});
Request Processing Pipeline
Databas koppling
En exempel för att koppla till en databas från klient-sida kan vara:
- Checking server up-status (Ok/Error)
- Loading connection bootstrap (Ok/Error)
- Starting encryption engine (Ok/Error)
- Creating VPN-tunnel (Ok/Error)
- Checking credentials (Ok/Error)
- Loading database handshake (Ok/Error)
- Try/catch connecting (Ok/Error)
- Checking connection status (Ok/Error)
Your are in!
Det kan implementeras med Promise, Callback eller Async/Await för att ha asynkronitet för processen att kopla till en databas.
// Exempel på en Promise som kopplar till en databas
function connectToDatabase() {
return new Promise((resolve, reject) => {
// Simulera en databasanslutning
setTimeout(() => {
const success = true; // Simulera en lyckad anslutning
if (success) {
resolve("Connected to database");
} else {
reject("Failed to connect to database");
}
}, 1000); // Simulera en fördröjning på 1 sekund
});
}
// Använda Promise
connectToDatabase()
.then((message) => {
console.log(message); // "Connected to database"
})
.catch((error) => {
console.error(error); // "Failed to connect to database"
});
// Exempel på en Async/Await som kopplar till en databas
async function connectToDatabase() {
try {
// Simulera en databasanslutning
setTimeout(() => {
const success = true; // Simulera en lyckad anslutning
if (success) {
resolve("Connected to database");
} else {
reject("Failed to connect to database");
}
}, 1000); // Simulera en fördröjning på 1 sekund
console.log(message); // "Connected to database"
} catch (error) {
console.error(error); // "Failed to connect to database"
}
}
connectToDatabase();
// Exempel på en Callback som kopplar till en databas
function connectToDatabase(callback) {
// Simulera en databasanslutning
setTimeout(() => {
const success = true; // Simulera en lyckad anslutning
if (success) {
callback(null, "Connected to database");
} else {
callback("Failed to connect to database", null);
}
}, 1000); // Simulera en fördröjning på 1 sekund
}
// Använda Callback i parametern
connectToDatabase((error, message) => {
if (error) {
console.error(error); // "Failed to connect to database"
} else {
console.log(message); // "Connected to database"
}
});
// Kan visas också
connectToDatabase((error, message) => { if (error) { console.error(error); } else { console log(message); } });
// BE AWARE OF CALLBACK HELL! Att man inte har massa callbacks för att det blir svårt att läsa koden
Databas koppling (ADODB)
ADODB är en databas koppling som används för att koppla till en mdb databas. Det är en del av Microsofts ActiveX Data Objects (ADO) och används för att hämta och manipulera data i databaser.
Exempel på hur man använder med express router:
// Importera express modul och skapa router
const express = require("express");
const router = express.Router();
// Importera ADODB modul
const ADODB = require("node-adodb");
// Skapa en ADODB databas koppling
router.get('/:id', (request, response) => {
// Id som man har satt i URL:en
const id = request.params.id;
// Koppla till databasen som ligger i /data/mdb/ mappen
const connection = ADODB.open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=./data/mdb/somedatabase.mdb;');
// En asynkron funktion som hämtar data från databasen
async function sqlQuery() {
const result = await connection.query(`SELECT * FROM somedatabase WHERE id = ${id}`);
// Testar om resultatet är tomt
if (result.length === 0) {
response.send("No data found");
return;
}
// Ta ut datan från resultatet
const date = result[0]['date'];
const text = result[0]['text'];
response.send(date);
response.write('<br>');
response.send(text);
}
// Anropa funktionen
sqlQuery();
});
Callstack
Callstack är en struktur som används för att hålla reda på vilka funktioner som har anropats och i vilken ordning. När en funktion anropas läggs den till i callstacken, och när den är klar tas den bort från callstacken. Det är viktigt att förstå hur callstacken fungerar för att kunna hantera asynkronitet och undvika problem som “callback hell”.
// Exempel på hur callstacken fungerar
function firstFunction() {
console.log("First function called");
secondFunction();
}
function secondFunction() {
console.log("Second function called");
thirdFunction();
}
function thirdFunction() {
console.log("Third function called");
}
Det här exemplet visar hur callstacken fungerar. När firstFunction
anropas läggs den till i callstacken, och när den är klar anropas secondFunction
, som också läggs till i callstacken. När secondFunction
är klar anropas thirdFunction
, som också läggs till i callstacken. När thirdFunction
är klar tas den bort från callstacken, och så vidare.
Ajax (Asynchronous JavaScript and XML)
Ajax tillåter interaction med server efter klient-sidan har laddat in. Det gör att man kan updatera sidan utan att behöva ladda om sidan.
Hur man använder:
// Exempel att hämta filen ajax_info.txt med Ajax och sätta in i elementet med id "demo"
function loadDoc() {
// Skapa en XMLHttpRequest objekt
const xhttp = new XMLHttpRequest();
// Sätta en callback funktion som körs när requesten är klar
xhttp.onload = function() {
// Sätta in innehållet i elementet med id "demo"
document.getElementById("demo").innerHTML = this.responseText;
}
// Öppna en GET request till filen ajax_info.txt
xhttp.open("GET", "ajax_info.txt", true);
// Skicka requesten
xhttp.send();
}
I modärn tid kan man använda Fetch API istället också.
Sessions och Cookies
Sessions används för att hålla reda på användarens status och information under en period. Det är viktigt för att kunna hantera inloggningar och andra användarspecifika funktioner på server-sidan. Sessions lagras på servern och en session ID skickas till klienten som en cookie. När klienten gör en begäran till servern skickas session ID:t med i begäran så att servern kan identifiera användaren.
Cookies är små textfiler som lagras på klientens dator och används för att lagra information om användaren. Cookies kan användas för att lagra sessions ID, inloggningsinformation och andra användarspecifika inställningar. Cookies har en utgångstid och kan raderas av användaren när som helst.
Exempel node express som använder sessions och cookies:
// Importera express modul och skapa router
const express = require("express");
const app = express();
const session = require("express-session");
const cookieParser = require("cookie-parser");
app.use(cookieParser());
app.use(session({secret: 'this-is-a-secret-token', resave: false, saveUninitialized: true}));
app.get('/', (req, res) => {
// Kolla om man är loggad in i session
if (req.session.loggedin) {
res.send('Welcome back!');
} else {
res.send('Please login to see this page!');
}
});
Asynkronitet och blocking code
Synchronus
Varje kodrad körs efter att föregående kodrad är avslutad. Man kan läsa koden uppifrån och ned och få en känsla för den ordning som koden exekveras i.
I synkrom programmering så blockar programmet när det väntar på input från användaren, eller när programmet läser en fil. Programexekveringen slutar tills det kommer input, från användaren eller tills dess filen är inläst.
Asynchronus
En central event loop styr exekveringen. Så fort en operation, en kodrad, blockar länas exekveringskontrollen över till event loopen. Exempel när vi låter användaren mata in något från tangentbordet, eller när vi läser och skriver till filer. Dessa är blockande operationer. Tanken är att event loopen tar över så fort någon exekvering blockar. Event loopen kan då lämna över exekveringen till en annan del i programmet som inte väntar, och på det sättet exekveras hela programmet snabbare.
Så fort något blockar så lämnas kontrollen över till de programdelar som inte blockar och kan exekveras.
Callback
Man kan ha funktioner som in-parameter. Den praktiken kalls “callback”. Det är en funktion som skickas som argument till en annan funktion. Denna funktion kan anropas när den andra funktionen är klar med sin uppgift. Det är ett sätt att hantera asynkronitet i JavaScript.
function functionOne(name, callback) {
callback(name);
}
function functionTwo(name) {
console.log("Hello " + name);
}
functionOne("World", functionTwo);
Man kan förkorta det att ha funktionen direkt som parameter.
function functionOne(name, callback) {
callback(name);
}
//Kallar functionOne -- Sätter function two direkt i parameter
functionOne("World", functionTwo(name) { console.log("Hello " + name);} );
Promises
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promises representerar är asynchronous operationer som kan göras i framtiden. Det är snyggare vis att göra än callbacks.
const myPromise = new Promise((resolve, reject) => {
// Gör något asynkront
const success = true; // Simulera en lyckad operation
if (success) {
resolve("Operation successful");
} else {
reject("Operation failed");
}
});
myPromise
.then((result) => {
console.log(result); // "Operation successful!"
return "Next step";
})
.then((newResult) => {
console.log(newResult); // "Next step"
})
.catch((error) => {
console.error(error); // Error handling
})
.finally(() => {
console.log("Promise completed"); // Runs regardless of success/failure
});
- Pending: Början av en promise. Den är varken uppfylld eller avvisad.
- Fulfilled: När en promise är uppfylld. Den har lyckats.
- Rejected: Operation misslyckades.
Man kan också göra Promise.all()
Promise.all([
promise1,
promise2,
promise3
])
.then((results) => {
// Alla promises har lyckats
console.log(results);
})
.catch((error) => {
// Någon promise misslyckades
console.error(error);
});
Promise.race() kan användas för att köra flera promises och få resultatet av den första som lyckas.
Promise.race([
promise1,
promise2,
promise3
])
.then((result) => {
// Den första som lyckades
console.log(result);
})
.catch((error) => {
// Någon promise misslyckades
console.error(error);
});
Async/Await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Async/Await är en syntaktisk socker för att hantera asynkron kod. Det gör koden mer läsbar och lättare att förstå. Det är ett sätt att skriva asynkron kod som ser ut som synkron kod.
async function myAsyncFunction() {
try {
const result = await myPromise; // Väntar på att promise ska uppfyllas
console.log(result); // "Operation successful!"
} catch (error) {
console.error(error); // Error handling
} finally {
console.log("Async function completed"); // Runs regardless of success/failure
}
}
DOM (Document Object Model)
DHTML (Dynamic HTML)
https://en.wikipedia.org/wiki/Dynamic_HTML
DHTML tillåter utvecklare att göra saker med DOM med att kombinera HTML, CSS och JavaScript.
- Animera text och dokumenter (ex. bild)
- Ha “tickers” för att uppdatera innehåll realtid
- Form funktionalitet som behövs inte verifieras av servern
- Ha dropdown menus och andra interaktiva element
DHTML är inte vanlig att använda i konversation för det har blivit standard.
DHTML har inga interaktioner med servern efter det är laddat på klient-sidan.
Att få en element i DOM’en kan göras med document.getElementById("id")
och document.getElementsByClassName("class")
. Och om man vill få attribut, innehåll eller utsende används .value
, .innerHTML
och .style
.
Man kan ha event listeners för element att ge olika funktionalitet för en element
element.addEventListener("event", function() {
// do something
});
// Eller
element.onclick = function() {
// do something
}
Man kan ha olika events som onclick
, onmouseover
, onmouseout
, onchange
, onfocus
, onblur
, onsubmit
och onload
. Dessa kan användas för att ge olika funktionalitet till element.
Man kan ersätta function orded med en arrow.
function functionOne(name) {
console.log("Hello " + name);
}
// Förkortad version med arrow function
functionOne = (name) => {
console.log("Hello " + name);
}
Det finns olika events för keybindings.
window.addEventListener("keydown", function(event) {
alert("Key pressed: " + event.key);
});
Former
När man försöker skicka filer i en form måste form element ha attribut enctype="multipart/form-data"