sandra-larsson
Educator Fullstack Developer Javascript at Chas Academy
JavaScript
const getData = function(url) {
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));
}
getData(url);
const getData = function(url) {
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));
}
getData(url);
const getData = async function(url) {
try {
const response = await fetch(url);
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
}
getData(url);
Varje instruktion måste avslutas innan nästa instruktion kan köras.
Fler processer kan alltså inte köras samtidigt.
const arr = [1,3,4,5,6,7]
const anotherArr = [1,3,4]
for(let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
console.log("For loop 1 done...")
for(let j = 0; j < anotherArrlength; j++) {
console.log(anotherArr[j])
}
console.log("For loop 2 done...")
En del rutiner tar tid. Exempel HTTP-requests eller hämta från databas. Hur hantera vi detta?
sånt som blockar!
Statement 1
Statement 2
Statement 3
Statement 4
HTTP REQUEST
🕰
HÄMTA FRÅN DB
🕰
BLOCKERANDE 👎
När man bygger webbapplikationer som efterfrågar från API:er eller en databas blir det här problemet mer påtagligt. Ingen användare vill att ett fönster ska "frysas" medan text eller bild laddas in.
I synkron programmering så blockar programmet när det väntar på input från användaren, eller när programmet hämtar från API/databas eller input från användaren.
För webbapplikationer handlar långa väntetider just om väntetid (inte beräkningstid) som hämta från API/databas. Här kommer alltså asynkron programmering i Javascript till sin stora nytta!
HTTP
förfrågan
väntar på respons
HTTP
förfrågan
Andra processer kan köras
HTTP svar
=> gör något med det
Statement 1
Statement 2
Statement 3
CALLBACK
HTTP REQUEST
🕰
ICKE-BLOCKERANDE 👍
HTTP REQUEST
Starta exekveringen nu, men avsluta senare
"BAKGRUNDEN"
Hur Javascriptmotorn håller reda på hur funktionen anropas. Vilka funktioner som körs och vilka funktioner som väntar på att köras o.s.v.
Callstack arbetar utifrån principen LIFO - last in first out.
När en funktion anropas kommer den att läggas till call stack, när den returnas kommer information om funktionen tas bort från call stack.
function firstFunction(){
console.log("Hello from firstFunction");
}
function secondFunction(){
firstFunction();
console.log("The end from secondFunction");
}
secondFunction();
function multiply(x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);
Loupe eller https://www.jsv9000.app/
Idén är att vi vill kunna sätta igång en exekvering av något nu
och sedan hantera det senare.
Detta gör att vårt UI inte blir blockerat utan användaren kan
fortfarande interagera med sidan medan andra saker sker i
bakgrunden.
- Vi vill ju äta precis när pannkakorna är klara
function makePancakes(callback) {
console.log("Making pancakes...");
setTimeout(() => {
callback(); //
}, 1500 );
}
makePancakes(() => {
console.log("Let's eat");
});
function doStep1(init, callback) {
const result = init + 1;
callback(result);
}
function doStep2(init, callback) {
const result = init + 2;
callback(result);
}
function doStep3(init, callback) {
const result = init + 3;
callback(result);
}
# Callbacks
function doOperation() {
doStep1(0, (result1) => {
doStep2(result1, (result2) => {
doStep3(result2, (result3) => {
console.log(`result: ${result3}`);
});
});
});
}
doOperation();
# Callbacks
Callbacks var sättet att bygga upp asynkron kod med innan ES6-
Blir svårt att debugga ifall det r många beroenden. Fått synonomen Callback hell.
let ajax = new XMLHttpRequest();
ajax.open('get', url);
ajax.onreadystatechange = function() {
if(ajax.status == 200 && ajax.readyState == 4) {
console.log('Result: ' + ajax.responseText);
}
}
ajax.send();
Föregångaren till Fetch API som baserade den asynkrona hanteringen med callbacks!
Ett Promise i JS är ett objekt som kommer returnera ett värde i framtiden.
Tänk på det som att man gör ett löfte att göra något.
Promises är bra att använda när man inte vet hur lång tid nåt
kommer ta, t.ex. ett request till ett API på en server.
Jobbintervju, eller LIA-intervju 😃
const data = fetch(url)
Fetch() startar processen för att hämta en resurs över HTTP/JSON-fil
Hantering av två möjliga tillstånd
fetch(url)
.then(response => response.json()) // Om svaret fås, konvertera svaret till JSON
.then(data => console.log(data)) // Hantera svaret
.catch(error => console.log(error)); // Hantera eventuella fel
Kasta ett mynt - krona simulerar resolved och klave reject.
const myPromise = new Promise((resolve, reject) => {
if (/* Everything works */) {
resolve("Success. Promise was resolved");
} else {
reject("Fail. Promise was rejected");
}
});
Ett Promise, rent konkret, är ett objekt som kommer returnera ett värde i framtiden.
Callbackfunktionen tar två argument, "resolve" och "reject".
Går det bra körs resolve(), annars körs reject()
// Promise chaining
myPromise.then((message) => {
console.log(message);
}).catch((message) => {
console.log(message);
});
För att hantera ett Promise kan vi använda then() och catch()
then() är en funktion som används för att hantera resultatet av Promise när den har lyckats
catch() är en funktion som används för att hantera resultatet av Promise när den har misslyckats.
fetch("https://jsonplaceholder.typicode.com/todos/")
.then((response) => response.json())
.then((json) => console.log(json))
.catch((error) => console.log(error));
Funktionen fetch() är inbyggd i (de allra flesta) webbläsare med Fetch API. Den används för att göra en HTTP-request till en given URL och den returnerar en Promise.
I varje then() måste resultat returneras som en ny Promise så att nästa then() kan hantera det.
catch() behöver inte returnera en ny Promise.
const promise = new Promise(function (resolve, reject) {
if (/* Everything works */) {
resolve("Success. Promise was resolved");
} else if {
if(undefined) {
throw new Error("An error occured!")
}
} else {
reject("Fail. Promise was rejected");
}
});
promise.catch((error) => {
console.error(error); // Expected output: An error occured!!
});
Throw används för att skapa ett undantag. Dess undantag tas emot i catch.
doSomething()
.then(function (result) {
return doSomethingElse(result);
})
.then(function (newResult) {
return doThirdThing(newResult);
})
.then(function (finalResult) {
console.log(`Got the final result: ${finalResult}`);
})
.catch(function(error) {
console.log(error)
});
När man vill exekvera relatera asynkron operationer efter varandra. Nästa then() startar när den tidigare är resolved. Resultatet måste returneras för att vara åtkomlig i nästa then()
Utöver resolve, reject, then och catch, så
finns det ytterligare sätt att hantera Promises
Promise.all() används för att invänta all data från inpassade
promises - väntar bara på att alla resolve:ar, om en ger fel så
avbryts det helt. Användbart när vi vill göra flera parallella asynkrona
anrop och få tillbaka svaren när de är klara.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The first promise has resolved');
resolve(10);
}, 1 * 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The second promise has resolved');
resolve(20);
}, 2 * 1000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('The third promise has resolved');
resolve(30);
}, 3 * 1000);
});
Promise.all([p1, p2, p3]).then((results) => {
const total = results.reduce((p, c) => p + c);
console.log(`Results: ${results}`);
console.log(`Total: ${total}`);
});
# PROMISES
Om man vill ha den promise av två som resolvas snabbast kan
man använda Promise.race(), då ignoreras den långsammare resolven kan se ut såhär:
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "Ettan vann!");
});
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "Tvåan vann!");
});
Promise.race([p1, p2]).then(value => {
console.log(value);
});
async function fn() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 3000);
});
let result = await promise; // wait until the promise resolves
console.log(result); // "done!"
}
fn(); //kör en funktion som tar 3 sekunder
async function fn() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 3000);
});
let result = await promise; // wait until the promise resolves (*)
console.log(result); // "done!"
}
// Kör 3 funktioner som borde ta 3 sekunder
// Nu tar alla 3 ungefär 3 sekunder
fn();
fn();
fn();
async function getData() {
let response = await fetch(url);
// Väntar på svar från server och
// lägger datat i json-format
let data = await response.json();
// Väntar på att json-datat görs
// om till ett objekt
console.log(data); // Skriver ut vårt data
}
getData();
Allmänt verktyg för felhantering
exempel
function isValidJSON(text) {
if (typeof text!=="string"){
return false;
}
try {
let json = JSON.parse(text);
console.log(json)
return (typeof json === 'object');
}
catch (error){
console.log(error)
return false;
}
}
isValidJSON(input)
async function getData() {
try { //Om promise inte blir "resolved" => gå till catch
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(err) { // promise "rejected"
console.log(err);
}
}
getData();
hantera resolved + reject med async funktion
async function getData() {
try { // Om ej lyckas, d.v.s ingen
// promise resolved => gå till catch
let response = await fetch(url);
let data = await response.json();
return data;
} catch(err) { // promise rejected
console.log(err);
}
}
async function renderData() {
const data = await getData();
console.log(data);
}
renderData();
returnera från en async funktion
async function getData() {
try {
// Om ej lyckas, d.v.s ingen
// promise resolved => gå till catch
let response = await fetch(`http://jsonplaceholder.typicode.com/comments`);
let data = await response.json();
return data;
} catch (err) {
// promise rejected
console.log(err);
}
}
getData().then(data => {
console.log(data);
});
Returna från async/await
By sandra-larsson