﻿1
00:00:01,300 --> 00:00:03,370
‫Kursleiter: Nehmen wir uns nun eine Minute Zeit, um mehr

2
00:00:03,370 --> 00:00:06,370
‫über die asynchrone Natur von Node. js,

3
00:00:06,370 --> 00:00:09,510
‫das absolut grundlegende Themen wie

4
00:00:09,510 --> 00:00:13,010
‫synchronen, asynchronen, blockierenden und nicht

5
00:00:13,010 --> 00:00:15,140
‫blockierenden Code umfasst.

6
00:00:15,140 --> 00:00:17,810
‫Und all dies wird wirklich wichtig

7
00:00:17,810 --> 00:00:21,090
‫sein, um alles zu verstehen, was in diesem

8
00:00:21,090 --> 00:00:22,503
‫Abschnitt auftaucht.

9
00:00:24,240 --> 00:00:27,620
‫Dieser Code, den wir in der letzten Vorlesung geschrieben

10
00:00:27,620 --> 00:00:31,830
‫haben, um eine Datei zu lesen und ihren Inhalt dann in

11
00:00:31,830 --> 00:00:34,400
‫einer Variablen zu speichern, war also

12
00:00:34,400 --> 00:00:36,840
‫so genannte synchron, was einfach

13
00:00:36,840 --> 00:00:41,330
‫bedeutet, dass jede Anweisung im Grunde nacheinander abgearbeitet wird, Zeile per Linie.

14
00:00:41,330 --> 00:00:42,540
‫In diesem

15
00:00:42,540 --> 00:00:45,630
‫Beispiel wird zuerst das Dateisystemmodul benötigt, dann

16
00:00:45,630 --> 00:00:47,630
‫wird die Datei gelesen und

17
00:00:47,630 --> 00:00:50,900
‫dann protokollieren wir das Ergebnis in der Konsole.

18
00:00:50,900 --> 00:00:53,340
‫Sie sehen also, dass jede

19
00:00:53,340 --> 00:00:57,340
‫Codezeile im Grunde auf das Ergebnis der vorherigen Zeile wartet.

20
00:00:57,340 --> 00:00:59,440
‫Dies kann insbesondere bei langsamen

21
00:00:59,440 --> 00:01:01,500
‫Operationen zu einem Problem werden,

22
00:01:01,500 --> 00:01:04,190
‫da jede Zeile die Ausführung des restlichen

23
00:01:04,190 --> 00:01:05,710
‫Codes blockiert.

24
00:01:05,710 --> 00:01:08,120
‫Daher sagen wir, dass

25
00:01:08,120 --> 00:01:12,290
‫synchroner Code auch als Blockierungscode bezeichnet wird, da eine

26
00:01:12,290 --> 00:01:15,080
‫bestimmte Operation nur ausgeführt werden kann,

27
00:01:15,080 --> 00:01:17,740
‫nachdem die vorherige abgeschlossen ist.

28
00:01:17,740 --> 00:01:20,850
‫Und wegen des Weges Node. js entwickelt wurde,

29
00:01:20,850 --> 00:01:24,220
‫wird dies zu einem großen Problem, wie wir auf der

30
00:01:24,220 --> 00:01:26,190
‫nächsten Folie im Detail sehen werden.

31
00:01:26,190 --> 00:01:28,500
‫Die Lösung für dieses Problem in

32
00:01:28,500 --> 00:01:32,160
‫Node besteht also darin, asynchronen, nicht blockierenden Code zu verwenden.

33
00:01:32,160 --> 00:01:35,380
‫In asynchronem Code laden wir also schwere Arbeit hoch,

34
00:01:35,380 --> 00:01:38,470
‫die im Wesentlichen im Hintergrund bearbeitet wird.

35
00:01:38,470 --> 00:01:40,820
‫Und wenn diese Arbeit erledigt

36
00:01:40,820 --> 00:01:43,370
‫ist, wird eine Callback-Funktion aufgerufen, die wir zuvor

37
00:01:43,370 --> 00:01:45,730
‫registriert haben, um das Ergebnis zu verarbeiten.

38
00:01:45,730 --> 00:01:47,540
‫Und während all dieser

39
00:01:47,540 --> 00:01:50,380
‫Zeit kann der Rest des Codes immer noch

40
00:01:50,380 --> 00:01:52,910
‫ausgeführt werden, ohne durch die schwere Aufgabe,

41
00:01:52,910 --> 00:01:55,820
‫die jetzt im Hintergrund läuft, blockiert zu werden.

42
00:01:55,820 --> 00:01:59,520
‫Das bedeutet also, dass wir effektiv in die

43
00:01:59,520 --> 00:02:01,620
‫Zukunft verschieben oder reagieren

44
00:02:01,620 --> 00:02:04,530
‫können, um den Code blockierungsfrei zu

45
00:02:04,530 --> 00:02:07,676
‫machen, und das ist natürlich viel besser.

46
00:02:07,676 --> 00:02:09,287
‫Macht Sinn?

47
00:02:09,287 --> 00:02:12,203
‫In diesem Beispiel verwenden wir

48
00:02:12,203 --> 00:02:16,390
‫also die asynchrone Funktion readFile, die eine Callback-Funktion akzeptiert.

49
00:02:16,390 --> 00:02:19,120
‫Dies beginnt mit dem Lesen der

50
00:02:19,120 --> 00:02:22,360
‫Datei im Hintergrund und geht dann sofort zur nächsten

51
00:02:22,360 --> 00:02:25,830
‫Anweisung über, die die String-lesende Datei an die Konsole ausgibt.

52
00:02:25,830 --> 00:02:30,530
‫Sie sehen also, wir blockieren die Hinrichtung hier nicht.

53
00:02:30,530 --> 00:02:33,860
‫Wenn die Datei schließlich vollständig gelesen ist, wird

54
00:02:33,860 --> 00:02:35,870
‫die Callback-Funktion aufgerufen,

55
00:02:35,870 --> 00:02:38,100
‫und die gelesenen Daten werden

56
00:02:38,100 --> 00:02:40,270
‫dann an die Konsole ausgegeben.

57
00:02:40,270 --> 00:02:41,890
‫Das ist also ganz

58
00:02:41,890 --> 00:02:43,893
‫anders als die synchrone Version, oder?

59
00:02:44,870 --> 00:02:46,710
‫Nun stellt sich hier

60
00:02:46,710 --> 00:02:49,490
‫die Frage, warum muss das eigentlich so sein?

61
00:02:49,490 --> 00:02:53,940
‫Was ist das Problem beim Blockieren der Codeausführung in Node. js?

62
00:02:53,940 --> 00:02:57,030
‫Oder mit anderen Worten, warum verwenden wir

63
00:02:57,030 --> 00:02:59,770
‫Callback in Node. js?

64
00:02:59,770 --> 00:03:01,523
‫Nun, lass es uns herausfinden.

65
00:03:03,110 --> 00:03:05,930
‫Um diese Fragen zu verstehen, müssen

66
00:03:05,930 --> 00:03:08,220
‫wir zunächst einmal verstehen, dass

67
00:03:08,220 --> 00:03:11,260
‫ein Node. js-Prozess, in

68
00:03:11,260 --> 00:03:13,760
‫dem unsere Anwendung ausgeführt wird,

69
00:03:13,760 --> 00:03:16,410
‫gibt es nur einen einzigen Thread.

70
00:03:16,410 --> 00:03:19,720
‫Und der Thread ist wie eine Reihe von Anweisungen, die

71
00:03:19,720 --> 00:03:22,200
‫in der CPU des Computers ausgeführt werden.

72
00:03:22,200 --> 00:03:25,200
‫Im Grunde ist der Thread also der Ort,

73
00:03:25,200 --> 00:03:29,270
‫an dem unser Code im Prozessor einer Maschine tatsächlich ausgeführt wird.

74
00:03:29,270 --> 00:03:33,120
‫Denken Sie also daran, Node. js ist im Grunde

75
00:03:33,120 --> 00:03:36,980
‫Single-Threaded und daher gibt es für jede Anwendung nur einen Thread.

76
00:03:36,980 --> 00:03:40,300
‫So ist Node. js wurde entwickelt.

77
00:03:40,300 --> 00:03:43,050
‫Das bedeutet, dass alle Benutzer, die

78
00:03:43,050 --> 00:03:46,960
‫auf Ihre Anwendung zugreifen, alle denselben Thread verwenden, also

79
00:03:46,960 --> 00:03:50,040
‫im Grunde genommen auf denselben Thread zugreifen.

80
00:03:50,040 --> 00:03:53,410
‫Bei jeder Interaktion mit der Anwendung wird der Code,

81
00:03:53,410 --> 00:03:55,860
‫der für jeden Benutzer ausgeführt

82
00:03:55,860 --> 00:03:59,810
‫wird, im selben Thread an derselben Stelle auf dem Computer

83
00:03:59,810 --> 00:04:02,490
‫ausgeführt, auf dem die Anwendung ausgeführt wird.

84
00:04:02,490 --> 00:04:04,900
‫Und das unabhängig davon, ob

85
00:04:04,900 --> 00:04:09,900
‫Sie fünf Benutzer haben, wie in diesem Diagramm, oder 5.000 oder 5 Millionen.

86
00:04:10,610 --> 00:04:12,080
‫Gut?

87
00:04:12,080 --> 00:04:15,310
‫Dies bedeutet auch, dass, wenn ein Benutzer den

88
00:04:15,310 --> 00:04:17,960
‫einzelnen Thread mit synchronem Code sperrt,

89
00:04:17,960 --> 00:04:19,640
‫wie wir gerade

90
00:04:19,640 --> 00:04:22,280
‫gesehen haben, alle anderen Benutzer warten

91
00:04:22,280 --> 00:04:24,680
‫müssen, bis die Ausführung abgeschlossen ist.

92
00:04:24,680 --> 00:04:27,010
‫Und das ist vielleicht kein großes

93
00:04:27,010 --> 00:04:29,800
‫Problem, wenn Sie etwa fünf Benutzer haben,

94
00:04:29,800 --> 00:04:33,350
‫aber es wird definitiv für Tausende oder sogar Millionen

95
00:04:33,350 --> 00:04:35,393
‫von Benutzern gleichzeitig sein.

96
00:04:36,440 --> 00:04:39,830
‫Stellen Sie sich also vor, ein Benutzer greift auf Ihre

97
00:04:39,830 --> 00:04:43,280
‫Anwendung zu und in Ihrem Code wird eine riesige synchrone

98
00:04:43,280 --> 00:04:46,630
‫Datei gelesen, deren Laden etwa eine Sekunde dauert.

99
00:04:46,630 --> 00:04:49,920
‫Dies bedeutet natürlich, dass für diese eine

100
00:04:49,920 --> 00:04:52,370
‫Sekunde alle anderen Benutzer warten

101
00:04:52,370 --> 00:04:57,370
‫müssen, da die gesamte Ausführung für diese eine Sekunde gesperrt ist.

102
00:04:57,490 --> 00:05:00,680
‫Wenn diese anderen Benutzer also einige einfache Aufgaben erledigen

103
00:05:00,680 --> 00:05:02,940
‫möchten, wie sich bei Ihrer Anwendung

104
00:05:02,940 --> 00:05:06,900
‫anmelden oder nur einige Daten anfordern, können sie dies nicht tun.

105
00:05:06,900 --> 00:05:11,150
‫Sie müssen warten, bis die Datei vollständig gelesen wurde.

106
00:05:11,150 --> 00:05:15,130
‫Erst dann können sie endlich die

107
00:05:15,130 --> 00:05:18,113
‫einfacheren Aufgaben nacheinander ausführen.

108
00:05:19,260 --> 00:05:23,290
‫Bitte beachten Sie, dass dies eine sehr vereinfachte Version dessen ist, was wirklich

109
00:05:23,290 --> 00:05:27,010
‫hinter den Kulissen von Node passiert. js, weshalb wir

110
00:05:27,010 --> 00:05:29,880
‫im nächsten Abschnitt auf all

111
00:05:29,880 --> 00:05:33,760
‫dies zurückkommen und ein noch tieferes Verständnis

112
00:05:33,760 --> 00:05:38,090
‫dafür bekommen, wie Node. js verarbeitet asynchronen Code unter der Haube.

113
00:05:38,090 --> 00:05:39,370
‫Aber an dieser

114
00:05:39,370 --> 00:05:42,170
‫Stelle reicht dies, um das Konzept zu verstehen.

115
00:05:42,170 --> 00:05:44,560
‫Es ist besser, hier Schritt für Schritt

116
00:05:44,560 --> 00:05:46,520
‫vorzugehen und es nicht

117
00:05:46,520 --> 00:05:49,220
‫von Anfang an zu unübersichtlich zu machen, okay?

118
00:05:49,220 --> 00:05:51,660
‫Wie auch immer, so würde

119
00:05:51,660 --> 00:05:54,620
‫sich die Situation mit synchronem Blockierungscode abspielen,

120
00:05:54,620 --> 00:05:58,460
‫was für Ihre Benutzer offensichtlich eine schreckliche Erfahrung ist.

121
00:05:58,460 --> 00:06:01,180
‫Es ist also wirklich Ihre Aufgabe als Entwickler,

122
00:06:01,180 --> 00:06:03,260
‫solche Situationen durch die Verwendung von

123
00:06:03,260 --> 00:06:05,113
‫asynchronem Code zu vermeiden.

124
00:06:07,150 --> 00:06:10,180
‫Für die gleiche Situation sollten wir natürlich die

125
00:06:10,180 --> 00:06:12,780
‫asynchrone Dateilesefunktion verwenden, die, anstatt den einzelnen

126
00:06:12,780 --> 00:06:15,190
‫Thread zu blockieren, die schwere

127
00:06:15,190 --> 00:06:17,700
‫Arbeit im Hintergrund verrichtet, wo sie

128
00:06:17,700 --> 00:06:20,170
‫im Grunde bleibt, bis sie die

129
00:06:20,170 --> 00:06:22,700
‫Daten aus der Datei gelesen hat.

130
00:06:22,700 --> 00:06:25,950
‫Natürlich registrieren wir dann auch eine

131
00:06:25,950 --> 00:06:29,490
‫Callback-Funktion, die aufgerufen wird, sobald die Daten vorliegen.

132
00:06:29,490 --> 00:06:32,130
‫Und in diesem Szenario können dann

133
00:06:32,130 --> 00:06:35,100
‫alle anderen Benutzer ihre Aufgaben in einem

134
00:06:35,100 --> 00:06:38,710
‫einzigen Thread nacheinander ausführen, während die Datei noch im

135
00:06:38,710 --> 00:06:40,390
‫Hintergrund gelesen wird.

136
00:06:40,390 --> 00:06:43,870
‫Sobald die Daten gelesen sind, wird natürlich

137
00:06:43,870 --> 00:06:46,240
‫unsere Callback-Funktion aufgerufen, die

138
00:06:46,240 --> 00:06:51,240
‫im Haupt-Single-Thread ausgeführt wird, um die gelesenen Daten zu verarbeiten.

139
00:06:51,380 --> 00:06:52,460
‫Und das ist es.

140
00:06:52,460 --> 00:06:54,720
‫Das ist ein Überblick darüber, wie Node. js verarbeitet

141
00:06:54,720 --> 00:06:58,000
‫asynchrones Verhalten, um das nicht blockierende I/O-Modell

142
00:06:58,000 --> 00:07:00,850
‫zu implementieren, über das wir in

143
00:07:00,850 --> 00:07:03,670
‫der Einführungsvorlesung gesprochen haben, in Ordnung?

144
00:07:03,670 --> 00:07:07,240
‫Und I/O steht einfach für Input-Output, was im

145
00:07:07,240 --> 00:07:10,810
‫Grunde Dinge wie der Zugriff auf das Dateisystem

146
00:07:10,810 --> 00:07:13,500
‫und die Bearbeitung von Netzwerkanfragen ist.

147
00:07:13,500 --> 00:07:16,470
‫Dies ist eigentlich der ganze Grund, warum Node. js ist vollständig

148
00:07:16,470 --> 00:07:18,830
‫auf Rückrufe ausgelegt, wie Sie im

149
00:07:18,830 --> 00:07:21,190
‫Verlauf des Kurses sehen werden.

150
00:07:21,190 --> 00:07:24,090
‫In anderen Programmiersprachen wie PHP funktioniert es ganz

151
00:07:24,090 --> 00:07:27,260
‫anders, weil man im Grunde genommen für jeden

152
00:07:27,260 --> 00:07:29,640
‫neuen Benutzer einen neuen Thread bekommt,

153
00:07:29,640 --> 00:07:32,020
‫was ein ganz anderes Paradigma

154
00:07:32,020 --> 00:07:34,600
‫ist und wirklich ganz anders funktioniert.

155
00:07:34,600 --> 00:07:37,620
‫Aber der Schöpfer von Node. js hat festgestellt,

156
00:07:37,620 --> 00:07:40,660
‫dass dieses Modell die beste Lösung zum Erstellen

157
00:07:40,660 --> 00:07:42,980
‫hochperformanter und skalierbarer Webanwendungen ist.

158
00:07:42,980 --> 00:07:46,810
‫Nun, als letzte Anmerkung hier, ist es wichtig zu wissen,

159
00:07:46,810 --> 00:07:48,830
‫dass, wenn wir Rückrufe

160
00:07:48,830 --> 00:07:53,380
‫in unserem Code verwenden, dies nicht automatisch asynchron macht, in Ordnung?

161
00:07:53,380 --> 00:07:56,520
‫Das Übergeben von Funktionen an andere

162
00:07:56,520 --> 00:07:58,780
‫Funktionen ist in

163
00:07:58,780 --> 00:08:01,830
‫JavaScript also ziemlich üblich, aber das

164
00:08:01,830 --> 00:08:05,110
‫macht sie natürlich nicht automatisch asynchron, okay?

165
00:08:05,110 --> 00:08:09,150
‫Dies funktioniert nur für einige Funktionen in der Node-API, wie

166
00:08:09,150 --> 00:08:11,210
‫die readFile-Funktion und viele,

167
00:08:11,210 --> 00:08:14,823
‫viele mehr, die die Leute in Zukunft erkunden werden.

168
00:08:16,610 --> 00:08:18,500
‫Und jetzt zum

169
00:08:18,500 --> 00:08:21,200
‫Schluss, da wir hier über asynchronen

170
00:08:21,200 --> 00:08:24,630
‫Code sprechen, noch eine letzte Anmerkung zu Callback-Funktionen.

171
00:08:24,630 --> 00:08:27,670
‫Dieses Callback-Modell, das wir gerade besprochen haben, bei

172
00:08:27,670 --> 00:08:29,370
‫dem eine Funktion aufgerufen

173
00:08:29,370 --> 00:08:32,300
‫wird, sobald die vorherige ihre Arbeit beendet

174
00:08:32,300 --> 00:08:36,970
‫hat, kann schnell zu schwer lesbarem und nicht zu verwaltendem Code führen.

175
00:08:36,970 --> 00:08:39,830
‫Nehmen Sie einfach dieses Beispiel, wo die zweite gelesene

176
00:08:39,830 --> 00:08:41,870
‫Datei von der ersten abhängt,

177
00:08:41,870 --> 00:08:44,800
‫dann die dritte gelesene Datei von der zweiten, und

178
00:08:44,800 --> 00:08:47,560
‫schließlich möchten wir die endgültigen Daten verwenden, um

179
00:08:47,560 --> 00:08:49,700
‫als Ergebnis eine Datei zu schreiben.

180
00:08:49,700 --> 00:08:52,690
‫Das sieht ziemlich verwirrend aus, oder?

181
00:08:52,690 --> 00:08:54,950
‫Ich meine, es wird gut

182
00:08:54,950 --> 00:08:57,330
‫funktionieren, aber es ist nur schwer

183
00:08:57,330 --> 00:09:00,110
‫zu argumentieren und das nur mit vier Ebenen.

184
00:09:00,110 --> 00:09:02,980
‫Stellen Sie sich vor, Sie hätten 10 oder

185
00:09:02,980 --> 00:09:05,850
‫20 Level, was eigentlich nicht ungewöhnlich ist.

186
00:09:05,850 --> 00:09:09,440
‫Jedenfalls nennen wir das die Callback-Hölle.

187
00:09:09,440 --> 00:09:11,370
‫Es ist ein so häufiges

188
00:09:11,370 --> 00:09:13,780
‫Problem, dass es bereits einen eigenen Namen hat.

189
00:09:13,780 --> 00:09:16,920
‫Und fällt Ihnen diese Dreiecksform hier auf?

190
00:09:16,920 --> 00:09:20,840
‫Das ist ein sehr klares Zeichen dafür, dass Sie sich in der Callback-Hölle befinden.

191
00:09:20,840 --> 00:09:24,350
‫Wie entkommen wir nun tatsächlich der Callback-Hölle?

192
00:09:24,350 --> 00:09:27,600
‫Nun, wir können fortschrittlichere Tools für den

193
00:09:27,600 --> 00:09:30,730
‫Umgang mit asynchronem Code verwenden,

194
00:09:30,730 --> 00:09:34,150
‫wie ES6-Versprechen oder noch besser ES8 async/await.

195
00:09:34,150 --> 00:09:36,320
‫Nun, das Modell, über das wir gerade gesprochen haben,

196
00:09:36,320 --> 00:09:37,890
‫wird immer noch dasselbe sein.

197
00:09:37,890 --> 00:09:39,960
‫Wir haben einfach elegantere Möglichkeiten,

198
00:09:39,960 --> 00:09:43,370
‫mit dem Code selbst umzugehen und ihn zu schreiben.

199
00:09:43,370 --> 00:09:45,830
‫Und es gibt einen ganzen

200
00:09:45,830 --> 00:09:50,090
‫optionalen Abschnitt davon später im Kurs über Versprechen und auch async/await,

201
00:09:50,090 --> 00:09:52,590
‫falls Sie damit nicht vertraut sind.

202
00:09:52,590 --> 00:09:55,140
‫Aber vorerst werden wir weiterhin

203
00:09:55,140 --> 00:09:57,900
‫Rückrufe verwenden, da Node ursprünglich verwendet

204
00:09:57,900 --> 00:10:00,100
‫und entwickelt wurde.

205
00:10:00,100 --> 00:10:02,030
‫Und jetzt, nachdem dies

206
00:10:02,030 --> 00:10:05,240
‫gesagt wurde, lassen Sie uns dieses asynchrone Modell zum

207
00:10:05,240 --> 00:10:07,233
‫ersten Mal in der Praxis verwenden.

