Skip to content

Commit

Permalink
efni viku 10
Browse files Browse the repository at this point in the history
  • Loading branch information
osk committed Oct 14, 2024
1 parent 28b195d commit b91ede0
Show file tree
Hide file tree
Showing 36 changed files with 2,244 additions and 0 deletions.
372 changes: 372 additions & 0 deletions namsefni/31.async/1.async.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,372 @@
---
title: Fyrirlestur – Ósamstillt forritun
---

# Fyrirlestur – Ósamstillt forritun

## Vefforritun 1 — TÖL107G

### Ólafur Sverrir Kjartansson, [osk@hi.is](mailto:osk@hi.is)

---

## Ósamstillt forritun (async programming)

* Þegar forritin okkar fara að nýta hluti sem eru ekki í minni þurfum við að beita öðrum aðferðum í forritun
* Það er _hratt_ að sækja hluti í minni, _hægara_ að sækja á disk og (oftast) enn _hægara_ að sækja yfir net
* Bíðum ekki eftir því að beiðni klárist, nýtum _ósamstillta forritun_ (asynchronous/async programming)

***

## Samstillt forritun

* Flest forrit sem þið hafið séð hingað til eru samstillt—þau keyra eina línu í einu, eitt fall í einu—eru línuleg
* Hægt að nota _þræði_, JavaScript hefur **ekki** stuðning við þá
* Notum async forritun með _event loop_ á einum þræði
* Höldum CPU ekki uppteknum á meðan beðið

***

![Dæmi um mismunandi forritun](img/control-io.svg "Mynd frá https://eloquentjavascript.net/11_async.html")

***

## Callbacks

* Ein leið til að vinna með async kóða, t.d. í atburðum
* Köllum í fall sem tekur langan tíma, eða verður kallað í seinna, með _callback_ argument
* Fallið kallar í _callback_ fall með niðurstöðu þegar búið
* Ef við köllum í annað fall sem tekur langan tíma úr _callback_ þurfum við annað callback o.s.fr. o.s.fr.

***

<!-- eslint-disable no-alert -->

```javascript
// snoozea í 5s, síðan 3s og að lokum 1s
setTimeout(() => {
alert('Vakna!');
setTimeout(() => {
alert('Vakna núna!');
setTimeout(() => {
alert('VAKNA!!');
}, 1000);
}, 3000);
}, 5000);
```

***

* Getum búið til almennt fall `snooze` sem birtir skilaboð eftir ákveðinn tíma
* Getur aukalega tekið við _callback_ falli sem keyrir í framhaldinu
* Verður aðeins læsilegra

***

<!-- eslint-disable no-alert -->

```javascript
function snooze(s, msg, callback) {
setTimeout(() => {
alert(msg);
if (callback) {
callback();
}
}, 1000 * s);
}

snooze(5, 'Vakna', () => {
snooze(3, 'Vakna núna!', () => {
snooze(1, 'VAKNA!!');
});
});
```

***

* [snooze dæmi](daemi/01.snooze.js)

---

## Promises

* [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) er hjúpun fyrir gildi sem _mun verða til_ í framtíðinni
* Gerir asynchronous forritun auðveldari
* Öðruvísi hugtak en callbacks, vinnum með hjúpuð gildi í staðinn fyrir eitthvað sem við köllum í framhaldi

***

* Þegar við skilgreinum Promise köllum við í:
* `resolve` með gildi þegar við höfum lokið aðgerð
* `reject` með villu ef eitthvað fer úrskeiðis

***

* Þegar við vinnum með promise skilgreinum við
* `then` callback til að vinna með gildið, fær skilagildi sem argument
* `catch` callback til að vinna með villu, fær villu sem argument
* `then` og `catch` eru föll á Promise

***

* Getum sent promise gildi á milli og bætt við `then` og `catch`!
* Ef búið er að uppfylla en við köllum í seinna, þá fáum við svarið

***

```javascript
const fifteen = Promise.resolve(15);
fifteen
.then(v => console.log(`Got ${v}`));
// → Got 15
setTimeout(() => {
fifteen
.then((value) => {
console.log('Sama svar, sekúndu seinna', value)
});
}, 1000);
```

***

* [promise dæmi](daemi/02.promise.js)

---

## Villur

* Villumeðhöndlun með callbacks verður hratt mjög ólæsileg og flókin
* Eitt argument fyrir hvað gerist ef við fáum gildi, annað fyrir villu
* Blöndum saman villumeðhöndlun og lógík
* Mjög mikið inndreginn kóði, _callback hell_

***

<!-- eslint-disable no-undef -->

```javascript
snooze(5, 'Vakna', () => {
if (ok) {
snooze(3, 'Vakna núna!', () => {
if (okok) {
snooze(1, 'VAKNA!!');
} else {
// villa
}
});
} else {
// villa
}
});
```

***

* `catch` eftir `then` í Promise sér um villur í öllum kóða sem á undan kemur
* Þurfum ekki að hafa villumeðhöndlun innan kóða sem sér um að bregðast við gildi

***

<!-- eslint-disable implicit-arrow-linebreak -->

```javascript
function futureMessage(msg) {
return new Promise((resolve, reject) => {
if (msg === 'foo') {
reject(new Error('No foo!'));
}

setTimeout(() =>
resolve(`${msg} from future`), 2000);
});
}

futureMessage('Hi!')
.then(msg => console.log(msg));
// "Hi! from future!" eftir 2 sek
```

***

<!-- eslint-disable no-undef -->

```javascript
futureMessage('foo')
.then(msg => console.log(msg))
.catch(e => console.log(e));
// "No foo!" strax
```

***

## Stöður á promise

Promise getur verið í einni af þrem stöðum:

* `pending`, verið að bíða eftir gildi
* `fulfilled`, búið að uppfylla loforð með gildi
* `rejected`, búið að hafna loforði með villu

***

<!-- eslint-disable no-undef -->

```javascript
const p = futureMessage('hmm');
function foo(promise) {
console.log(promise);

promise.then(msg => console.log(msg));

return 'Handling promise...';
}
foo(p);
// Promise { ... }
// "Handling promise..."
// "hmm from the future!" eftir 2 sek
```

***

<!-- eslint-disable no-alert -->

```javascript
function snooze(s, msg) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(msg);
}, s * 1000);
});
}

snooze(5, 'Vakna')
.then(msg => alert(msg))
.then(() => snooze(3, 'Vakna núna!'))
.then(msg => alert(msg))
.then(() => snooze(1, 'VAKNA!!!'))
.then(msg => alert(msg));
```

***

* [promise og villumeðhöndlun dæmi](daemi/03.future-message.js)
* [snooze dæmi með promises](daemi/04.snooze-promise.js)

---

## Promise.all

* `Promise.all` tekur við fylki af Promise og skilar Promise
* Ef eitthvert rejactarar er Promise rejectað
* Niðurstaða er fylki með niðurstöðu í réttri röð m.v. uppruna

***

## Promise.race

* `Promise.race` tekur við fylki af Promise og skilar Promise
* Skilar niðurstöðu úr fyrsta Promise sem lýkur eða rejectar

***

<!-- eslint-disable no-undef -->

```javascript
const snoozefest = Promise.all([
snooze(5, 'Vakna'),
snooze(3, 'Vakna núna!'),
snooze(1, 'VAKNA!!!'),
])
.then(result => console.log(result));

console.log(snoozefest);
// Promise {pending}
// 5s seinna..
// ["Vakna", "Vakna núna!", "VAKNA!!!"]
```

***

<!-- eslint-disable no-undef -->

```javascript
// snooze eins og áður

Promise.race([
snooze(5, 'Vakna'),
snooze(3, 'Vakna núna!'),
snooze(1, 'VAKNA!!!'),
])
.then(result => console.log(result));

// 1s seinna..
// "VAKNA!!!"
```

***

* [all og race dæmi](daemi/05.all-race.js)

---

## async og await

* [`async await`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) er önnur leið til að vinna með async kóða
* Leyfir okkur að _bíða_ eftir async aðgerð í línulegu flæði
* Merkjum föll sem þarf að bíða eftir með `async`
* Merkjum að við ætlum að bíða með `await`
* Grípum villur með `try catch`

***

<!-- eslint-disable no-undef, no-alert -->

```javascript
// snooze fall eins og áður
async function snoozer() {
alert(await snooze(5, 'Vakna'));
alert(await snooze(3, 'Vakna núna'));
alert(await snooze(1, 'VAKNA!!!'));
}

snoozer();
```

***

<!-- eslint-disable no-undef -->

```javascript
// futureMessage eins og áður
async function future() {
try {
const res = await futureMessage('foo');
console.log(res);
} catch (e) {
console.log(e);
}
}

future();
```

***

* Getum ekki notað `await` í global scope—verður að vera innan `async` falls
* `async` fallið skilar Promise!
* `async await` er _syntactic sugar_ fyrir Promise
* Ættum að hafa `catch` á það fall til að vera örugg um að missa ekki af villum

***

## async forritun

* Async forritun er erfið til að byrja með
* Lærum ekki á einum degi eða einni viku en margt af því sem við gerum á vefnum **er** async
* Sjáum dæmi í atburðum og _ajax_ beiðnum
* Förum enn dýpra í vefforritun 2

***

* [async await dæmi](daemi/06.futureMessage-async.js)
* [snooze dæmi með async await](daemi/07.snooze-async.js)
6 changes: 6 additions & 0 deletions namsefni/31.async/daemi/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
rules: {
// leyfum alert()
'no-alert': 0,
},
};
Loading

0 comments on commit b91ede0

Please sign in to comment.