mirror of
https://github.com/TheTaz25/denis.ergin.git
synced 2025-07-06 11:18:49 +00:00
315 lines
No EOL
11 KiB
Text
315 lines
No EOL
11 KiB
Text
<section>
|
|
<section>
|
|
<h2>Promises</h2>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Wie bereits zuvor erwähnt sind Promises ein <strong>Versprechen, dass etwas in er Zukunft fertig sein wird (Funktion)</strong>.</p>
|
|
<p>In heutzutage modernen Browsern ist jede lang-laufende Operation hinter einem solchen Promise versteckt.</p>
|
|
<p>Promises sorgen dafür das eine Funktion (Message) in die Queue gesteckt wird und das der Event-Loop diese später ausführt.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Ein Promise zu erstellen ist relativ simpel</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise();
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Dieses Promise macht nun aber nicht viel. Ein Promise benötigt eine Funktion die im Hintergrund ausgeführt wird.</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise(() => {
|
|
console.log('Hallo Welt!');
|
|
});
|
|
</code></pre>
|
|
<p>Wir sollten beim ausführen dann ein "Hallo Welt!" in den Developer Tools sehen</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Wie sieht das nun aber alles aus wenn wir schauen wollen in welcher Reihenfolge das alles ausgeführt wird?</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise(() => {
|
|
console.log('Hallo Welt!');
|
|
});
|
|
|
|
console.log('Komme ich davor oder danach?');
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Ein Promise macht auch nicht mehr als den Callback auszuführen und auf ein Resultat zu warten.</p>
|
|
<p>Wenn es nichts gibt auf das man warten muss, ist ein Promise auch sofort abgeschlossen.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Bevor wir weiter machen, gehen wir auf den Callback des Promises näher ein.</p>
|
|
<p>Dieser Callback erhält nämlich 2 Parameter, die wiederrum Callbacks sind</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const p = new Promise((resolve, reject) => {
|
|
// ???
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Oft werden diese 2 Callbacks als <code>resolve</code> und <code>reject</code> definiert.</p>
|
|
<p>Schauen wir mal, was die Variable als Inhalt hat, in der wir dieses Promise packt:</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise(() => {
|
|
console.log('Hallo Welt!');
|
|
});
|
|
|
|
// Promise { <state>: "pending" }
|
|
console.log(myPromise);
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Das Promise hat einen Zustand der in "pending" hängt.</p>
|
|
<p>Dieser Zustand wird sich in dieser Form so auch nicht mehr ändern.</p>
|
|
<p>Hierfür sind die Callback-Funktionen <code>resolve & reject</code> gedacht.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Rufen wir mal die Funktion <code>resolve</code> innerhalb des Promises auf</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve) => {
|
|
console.log('Hallo Welt!');
|
|
resolve();
|
|
});
|
|
|
|
// Promise { <state>: "fulfilled", <value>: undefined }
|
|
console.log(myPromise);
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Die Promise ist nun <strong>fulfilled</strong> und scheint einen <code>value</code> zu beinhalten, der in diesem Fall <code>undefined</code> ist.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Sehen wir uns noch kurz an, wenn der Promise <strong>rejected</strong> wird</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((_, reject) => {
|
|
console.log('Hallo Welt!');
|
|
reject();
|
|
});
|
|
|
|
// Promise { <state>: "rejected", <value>: undefined }
|
|
console.log(myPromise);
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Gut, wir wissen nun dass der Promise "rejected" wurde, aber was heißt das genau?</p>
|
|
<p>Nun, Promises funktionieren ein wenig anders als einfach aufgerufene Funktionen.</p>
|
|
<p>Wenn wir die Variable <code>myPromise</code> untersuchen, sehen wir keine Möglichkeit, auf den Zustand oder den Wert zuzugreifen.</p>
|
|
<p>Aber es gibt ein paar Funktionen: <code>then, catch & finally</code>.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Wir können nur auf Resultate und den Allgemeinen Ausgang eines Promise reagieren indem wir mit diesen Funktionen arbeiten.</p>
|
|
<p>Diese Funktionen sind <code>chainable</code>. Wir können mehrere <code>.then & .catch</code> nacheinander aufrufen.</p>
|
|
<p>Wenn ein Promise erfolgreich ist und <code>resolve</code> aufruft, wird die Funktion in <code is:raw>.then(() => {})</code> aufgerufen</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Sollte das Promise nicht erfolgreich gewesen sein und hat <code>reject()</code> aufgerufen, so wird <code is:raw>.catch(() => {})</code> aufgerufen.</p>
|
|
<p>Wir können nicht aus einem Promise "ausbrechen". Wir können aber Resultate aus einem Promise zu jederzeit in den äußeren Scope verschieben und weitere Funktionen aufrufen.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Sehen wir uns das ganze nun in Aktion an:</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
resolve();
|
|
});
|
|
|
|
myPromise.then(() => {
|
|
console.log('Das war erfolgreich!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Der Fehlerfall ist auch leicht:</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
reject();
|
|
});
|
|
|
|
myPromise.catch(() => {
|
|
console.log('Das war diesmal NICHT erfolgreich!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Führen wir beide Varianten einmal zusammen:</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
reject();
|
|
});
|
|
|
|
myPromise
|
|
.then(() => {
|
|
console.log('Das ging mal gut!');
|
|
})
|
|
.catch(() => {
|
|
// Durch das reject landen wir nur hier!
|
|
console.log('Das war diesmal NICHT erfolgreich!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Das <code>catch</code> muss aber nicht das Ende sein, wenn wir nach dem <code>catch</code> noch etwas ausführen wollen, können wir einfach mit <code>.then</code> weiter machen.</p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
reject();
|
|
});
|
|
|
|
myPromise
|
|
.then(() => {
|
|
console.log('Das ging mal gut!');
|
|
})
|
|
.catch(() => {
|
|
console.log('Das war diesmal NICHT erfolgreich!');
|
|
})
|
|
.then(() => {
|
|
console.log('Es gibt mehr danach!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Das weitere <code>.then</code> und <code>.catch</code> aufgerufen werden können, hat einen entscheidenden Vorteil:</p>
|
|
<p>Wir können in <code>.then</code> und <code>.catch</code> einen Fehler werfen um ein anderes <code>.catch auszulösen.</code></p>
|
|
<p>Gleichzeitig bedeutet ein nicht vorhanden sein eines Errors, dass das nächste <code>.then</code> aufgerufen wird.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
resolve();
|
|
});
|
|
|
|
myPromise
|
|
.then(() => {
|
|
console.log('Das ging mal gut!');
|
|
throw new Error('Pech gehabt!');
|
|
})
|
|
.catch(() => {
|
|
console.log('Das war diesmal NICHT erfolgreich!');
|
|
})
|
|
.then(() => {
|
|
console.log('Es gibt mehr danach!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Um am Ende auf jeden Fall eine Funktion auszuführen gibt es zu guter letzt noch die Funktion <code>.finally</code>.</p>
|
|
<p>Der Aufruf sorgt dafür, dass in jedem Fall - egal ob ein Fehler geworfen wurde oder nicht - Code ausgeführt wird.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
resolve();
|
|
});
|
|
|
|
myPromise
|
|
.then(() => {
|
|
console.log('Das ging mal gut!');
|
|
})
|
|
.catch(() => {
|
|
console.log('Das war diesmal NICHT erfolgreich!');
|
|
})
|
|
.finally(() => {
|
|
console.log('Ich geschehe immer!');
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Parameter in <code>.catch</code> und <code>.then</code></p>
|
|
<p>Wir erhalten in diesen beiden Funktionen Informationen.</p>
|
|
<p><code>.catch</code> erhält in der Regel den Error der davor geworfen wurde, oder aber was in die Funktion <code>reject</code> mitgegeben wurde.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const p = new Promise((_, reject) => {
|
|
reject('Zum Scheitern verdonnert');
|
|
});
|
|
|
|
p.catch((reason) => {
|
|
console.log(reason);
|
|
throw new Error('Für immer');
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Das gleiche Funktioniert auch mit <code>resolve()</code> und <code>.then()</code></p>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const p = new Promise((resolve) => {
|
|
resolve(42);
|
|
});
|
|
|
|
p.then((zahl) => {
|
|
console.log(zahl);
|
|
return "Die einzig wahre Zahl";
|
|
})
|
|
.then((x) => {
|
|
console.log(x);
|
|
});
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<p>Ein Konkretes Beispiel</p>
|
|
<p>Nachfolgend lesen wir den Inhalt aus dem System-Clipboard aus. Die Funktionalität, die uns der Browser dafür gibt, liefert einen Promise.</p>
|
|
</section>
|
|
|
|
<section>
|
|
<pre class="js"><code data-trim data-line-numbers is:raw>
|
|
const into = document.getElementById('clipboard-result');
|
|
document.getElementById('clipboard-paste').onclick = function () {
|
|
navigator.clipboard.readText()
|
|
.then((clipboardText) => {
|
|
into.innerText = `Kopierter Text:\n${clipboardText}`;
|
|
})
|
|
.catch((err) => {
|
|
into.innerText = `Fehler beim lesen des Clipboards: ${err}`;
|
|
});
|
|
}
|
|
</code></pre>
|
|
|
|
<button id="clipboard-paste">
|
|
Paste
|
|
</button>
|
|
|
|
<div id="clipboard-result">
|
|
Ergebnis...
|
|
</div>
|
|
|
|
<script>
|
|
const into = document.getElementById('clipboard-result')!;
|
|
document.getElementById('clipboard-paste')!.onclick = function () {
|
|
navigator.clipboard.readText()
|
|
.then((clipboardText) => {
|
|
into.innerText = `Kopierter Text:\n${clipboardText}`;
|
|
})
|
|
.catch((err) => {
|
|
into.innerText = `Fehler beim lesen des Clipboards: ${err}`;
|
|
});
|
|
}
|
|
</script>
|
|
</section>
|
|
</section> |