


Zusammenfassung und Weitergabe, um mehrere Schlüsselknoten von NodeJS zu verstehen
Dieser Artikel ist ein persönliches Verständnis von nodejs in der tatsächlichen Entwicklung und beim Lernen. Er ist jetzt zum späteren Nachschlagen zusammengestellt. Es wäre mir eine Ehre, wenn er Sie inspirieren könnte.
Nicht blockierende E/A
E/A: Eingabe/Ausgabe, die Eingabe und Ausgabe eines Systems.
Ein System kann als Individuum verstanden werden, beispielsweise als eine Person. Wenn Sie sprechen, ist es der Output, und wenn Sie zuhören, ist es der Input.
Der Unterschied zwischen blockierender und nicht blockierender E/A besteht darin, ob das System im Zeitraum von der Eingabe bis zur Ausgabe andere Eingaben empfangen kann. Das Folgende sind zwei Beispiele, um zu veranschaulichen, was blockierende I/O und nicht-blockierende I/O sind:
1 Mahlzeiten zubereiten
Zuerst müssen wir den Umfang eines Systems bestimmen. In diesem Beispiel stellt sich die Cafeteria-Tante ein System vor, bei dem der Kellner im Restaurant bestellt und das Essen serviert.
Wenn Sie dann zwischen der Bestellung und dem Servieren von Speisen die Bestellungen anderer Personen annehmen können, können Sie feststellen, ob es sich um blockierende oder nicht blockierende E/A handelt. Für die Cafeteria-Tante kann sie beim Bestellen nicht für andere Schüler bestellen. Erst nachdem der Student die Bestellung abgeschlossen und das Geschirr serviert hat, kann er die Bestellung des nächsten Schülers annehmen, sodass die Cafeteria-Tante den I/O sperrt.
Für den Restaurantkellner kann er den nächsten Gast nach der Bestellung und bevor der Gast das Gericht serviert, bedienen, sodass der Kellner über nicht blockierende E/A verfügt.
2. Hausarbeit erledigenZu diesem Zeitpunkt müssen Sie nicht auf die Waschmaschine warten, sondern können den Schreibtisch und die Kleidung aufräumen Zu diesem Zeitpunkt wird die Wäsche aufgehängt, dann dauert es insgesamt nur 25 Minuten.
Wäsche ist eigentlich ein nicht blockierender I/O. Zwischen dem Einlegen der Kleidung in die Waschmaschine und dem Beenden des Waschvorgangs können Sie andere Dinge tun.
Der Schlüssel zum Verständnis nicht blockierender E/A ist :
Bestimmen Sie eine Systemgrenze
für E/A. Dies ist sehr kritisch, wenn das System wie im obigen Restaurantbeispiel erweitert wird, wenn das System auf das gesamte Restaurant ausgeweitet wird, dann wird der Koch definitiv ein blockierender I/O sein.- Können während des I/O-Prozesses andere I/Os durchgeführt werden?
- NodeJS nicht blockierende E/A
Wie manifestiert sich die nicht blockierende E/A von NodeJS? Wie bereits erwähnt, besteht ein wichtiger Punkt beim Verständnis nicht blockierender E/A darin, zunächst eine Systemgrenze des Knotens zu bestimmen.
Wenn das Architekturdiagramm unten nach Thread-Wartung unterteilt ist, ist die gepunktete Linie links der NodeJS-Thread und die gepunktete Linie rechts der C++-Thread.
Jetzt muss der Nodejs-Thread die Datenbank abfragen. Dies ist ein typischer E/A-Vorgang. Er wird nicht auf die Ergebnisse des E/A-Vorgangs warten und eine große Menge an Daten verteilen Rechenleistung für andere zu berechnende C++-Threads. Warten Sie, bis das Ergebnis ausgegeben wird, und geben Sie es an den NodeJS-Thread zurück. Bevor Sie das Ergebnis erhalten, kann der NodeJS-Thread auch andere E/A-Vorgänge ausführen, sodass er nicht blockiert.entspricht dem linken Teil als Kellner und dem C++-Thread als Chef.
Die nicht blockierende E/A des Knotens wird also durch den Aufruf von C++-Worker-Threads abgeschlossen.Wie benachrichtige ich den NodeJS-Thread, wenn der C++-Thread das Ergebnis erhält? Die Antwort ist
ereignisgesteuert.
EreignisgesteuertBlockierung
: Der Prozess schläft während der E/A und wartet auf den Abschluss der E/A, bevor er mit dem nächsten Schritt fortfährt;
Nicht blockierend: Die Funktion kehrt während der I/O sofort zurück /O, und der Prozess wartet nicht auf den E/A-Abschluss. Um dann das zurückgegebene Ergebnis zu erfahren, müssen Sie den
Ereignistreiberverwenden. Das sogenannte
Ereignisgesteuertekann als das gleiche verstanden werden wie das Front-End-Klickereignis. Ich schreibe zuerst ein Klickereignis, weiß aber nicht, wann es ausgelöst wird. Der Hauptthread führt die ereignisgesteuerte Funktion aus. Dieser Modus ist auch ein Beobachtermodus, das heißt, ich höre mir zuerst das Ereignis an und führe es dann aus, wenn es ausgelöst wird.
Wie implementiert man also Event Drive? Die Antwort ist Asynchrone Programmierung.
Asynchrone ProgrammierungWie oben erwähnt, verfügt NodeJS über eine große Anzahl nicht blockierender E/A, daher müssen die Ergebnisse nicht blockierender E/A über Rückruffunktionen abgerufen werden.
Diese Methode verwendet Rückruffunktionen ist asynchrone Programmierung. Der folgende Code erhält beispielsweise Ergebnisse über eine Rückruffunktion:glob(__dirname+'/**/*', (err, res) => {
result = res
console.log('get result')
})
Nach dem Login kopieren
Spezifikation des Callback-Funktionsformats
Der erste Parameter der NodeJS-Callback-Funktion ist Fehler, und die nachfolgenden Parameter sind das Ergebnis. Warum das tun?
try {
interview(function () {
console.log('smile')
})
} catch(err) {
console.log('cry', err)
}
function interview(callback) {
setTimeout(() => {
if(Math.random() <p>Nach der Ausführung wurde es nicht abgefangen und der Fehler wurde global ausgelöst, was zum Absturz des gesamten NodeJS-Programms führte. </p><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/image/244/886/980/1657110712466688.png" class="lazy" title="1657110712466688.png" alt="Zusammenfassung und Weitergabe, um mehrere Schlüsselknoten von NodeJS zu verstehen"></p><p> wird von try Catch nicht erfasst, da setTimeout die Ereignisschleife erneut öffnet. Jedes Mal, wenn eine Ereignisschleife geöffnet wird, wird ein Aufrufstapelkontext neu generiert, der zum Aufrufstapel der vorherigen Ereignisschleife und der Rückruffunktion gehört Wenn setTimeout ausgeführt wird, ist der Aufrufstapel anders. In diesem neuen Aufrufstapel gibt es keinen Try-Catch, daher wird der Fehler global ausgelöst und kann nicht abgefangen werden. Weitere Informationen finden Sie in diesem Artikel. Probleme bei der Verwendung asynchroner Warteschlangen für Try Catch. <a href="https://juejin.cn/post/6995749646366670855" target="_blank" title="https://juejin.cn/post/6995749646366670855"></a>Was sollen wir also tun? Verwenden Sie den Fehler als Parameter: </p><pre class="brush:php;toolbar:false">function interview(callback) {
setTimeout(() => {
if(Math.random() <p> Dies ist jedoch problematischer und muss im Rückruf beurteilt werden, sodass eine ausgereifte Konvention erstellt wird. Der erste Parameter ist err erfolgreich. </p><pre class="brush:php;toolbar:false">function interview(callback) {
setTimeout(() => {
if(Math.random() <p></p>Asynchrone Prozesssteuerung<h3 data-id="heading-5">
<strong></strong>Die Callback-Schreibmethode von NodeJS bringt nicht nur Callback-Bereiche mit sich, sondern auch Probleme mit der asynchronen Prozesssteuerung. </h3><p>Asynchrone Prozesssteuerung bezieht sich hauptsächlich auf die Handhabung der Parallelitätslogik, wenn Parallelität auftritt. Nehmen wir weiterhin das obige Beispiel: Wenn Ihr Kollege zwei Unternehmen interviewt, wird er erst dann von dem dritten Unternehmen interviewt, wenn er erfolgreich zwei Unternehmen interviewt hat. Wie schreibt man diese Logik? Es ist notwendig, jede Variable count:<strong><pre class="brush:php;toolbar:false">var count = 0
interview((err) => {
if (err) {
return
}
count++
if (count >= 2) {
// 处理逻辑
}
})
interview((err) => {
if (err) {
return
}
count++
if (count >= 2) {
// 处理逻辑
}
})
Nach dem Login kopieren wie die obige Methode zu unterstützen, was sehr mühsam und hässlich ist. Daher erschienen später die Schreibmethoden Promise und Async/Await.
Versprechenglob(__dirname+'/**/*', (err, res) => { result = res console.log('get result') })
try { interview(function () { console.log('smile') }) } catch(err) { console.log('cry', err) } function interview(callback) { setTimeout(() => { if(Math.random() <p>Nach der Ausführung wurde es nicht abgefangen und der Fehler wurde global ausgelöst, was zum Absturz des gesamten NodeJS-Programms führte. </p><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/image/244/886/980/1657110712466688.png" class="lazy" title="1657110712466688.png" alt="Zusammenfassung und Weitergabe, um mehrere Schlüsselknoten von NodeJS zu verstehen"></p><p> wird von try Catch nicht erfasst, da setTimeout die Ereignisschleife erneut öffnet. Jedes Mal, wenn eine Ereignisschleife geöffnet wird, wird ein Aufrufstapelkontext neu generiert, der zum Aufrufstapel der vorherigen Ereignisschleife und der Rückruffunktion gehört Wenn setTimeout ausgeführt wird, ist der Aufrufstapel anders. In diesem neuen Aufrufstapel gibt es keinen Try-Catch, daher wird der Fehler global ausgelöst und kann nicht abgefangen werden. Weitere Informationen finden Sie in diesem Artikel. Probleme bei der Verwendung asynchroner Warteschlangen für Try Catch. <a href="https://juejin.cn/post/6995749646366670855" target="_blank" title="https://juejin.cn/post/6995749646366670855"></a>Was sollen wir also tun? Verwenden Sie den Fehler als Parameter: </p><pre class="brush:php;toolbar:false">function interview(callback) { setTimeout(() => { if(Math.random() <p> Dies ist jedoch problematischer und muss im Rückruf beurteilt werden, sodass eine ausgereifte Konvention erstellt wird. Der erste Parameter ist err erfolgreich. </p><pre class="brush:php;toolbar:false">function interview(callback) { setTimeout(() => { if(Math.random() <p></p>Asynchrone Prozesssteuerung<h3 data-id="heading-5"> <strong></strong>Die Callback-Schreibmethode von NodeJS bringt nicht nur Callback-Bereiche mit sich, sondern auch Probleme mit der asynchronen Prozesssteuerung. </h3><p>Asynchrone Prozesssteuerung bezieht sich hauptsächlich auf die Handhabung der Parallelitätslogik, wenn Parallelität auftritt. Nehmen wir weiterhin das obige Beispiel: Wenn Ihr Kollege zwei Unternehmen interviewt, wird er erst dann von dem dritten Unternehmen interviewt, wenn er erfolgreich zwei Unternehmen interviewt hat. Wie schreibt man diese Logik? Es ist notwendig, jede Variable count:<strong><pre class="brush:php;toolbar:false">var count = 0 interview((err) => { if (err) { return } count++ if (count >= 2) { // 处理逻辑 } }) interview((err) => { if (err) { return } count++ if (count >= 2) { // 处理逻辑 } })
Die aktuelle Ereignisschleife kann das Ergebnis nicht abrufen, aber die zukünftige Ereignisschleife wird Ihnen das Ergebnis liefern. Es ist dem sehr ähnlich, was ein Drecksack sagen würde.
Versprechen ist nicht nur ein Drecksack, sondern auch eine Zustandsmaschine:ausstehenderfüllt/gelöst
- abgelehnt
const pro = new Promise((resolve, reject) => { setTimeout(() => { resolve('2') }, 200) }) console.log(pro) // 打印:Promise { <pending> }</pending>
Nach dem Login kopieren- dann & .catch
gelöstes Zustandsversprechen ruf den ersten später an Ein Versprechen im dann
abgelehnten Zustand ruft den ersten Catch auf.- Jedes Versprechen im Ablehnungszustand, dem nicht .catch folgt, führt zu einem globalen Fehler in der Browser- oder Knotenumgebung. „uncaught“ stellt einen nicht erfassten Fehler dar.
ein neues Versprechen zurückgeben Der Endzustand des Versprechens wird durch die Ausführungsergebnisse der Callback-Funktionen von then und Catch bestimmt:
Wenn die Callback-Funktion immer throw new ist Fehler, das Versprechen ist im Status „Abgelehnt“
Wenn die Rückruffunktion immer zurückkehrt, befindet sich das Versprechen im gelösten Zustand- Aber wenn die Rückruffunktion immer ein Versprechen zurückgibt, stimmt das Versprechen mit dem Versprechensstatus der Rückruffunktion überein
- .
-
Der Status von Versprechen1 wird durch den Status des Gegenzugsversprechens bestimmt, d. h. durch den Status von Versprechen1, nachdem das Gegenzugsversprechen ausgeführt wurde. Was sind die Vorteile davon? Dies kann „das Problem der Rückrufhölle lösen“.
function interview() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('success') } else { reject(new Error('fail')) } }) }) } var promise = interview() var promise1 = promise.then(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('accept') }, 400) }) })
Nach dem Login kopierenvar promise = interview() .then(() => { return interview() }) .then(() => { return interview() }) .then(() => { return interview() }) .catch(e => { console.log(e) })
Nach dem Login kopierenthen Wenn der Status des zurückgegebenen Versprechens „Abgelehnt“ ist, wird der erste Catch aufgerufen und der nachfolgende Catch wird nicht aufgerufen. Denken Sie daran: Abgelehnte Anrufe sind der erste Fang, gelöste Anrufe dann der erste.
Versprechen löst asynchrone Prozesssteuerung
Wenn Versprechen nur dazu dienen, Höllenrückrufe zu lösen, ist es zu klein, um Versprechen zu unterschätzen. Die Hauptfunktion von Versprechen besteht darin, asynchrone Prozesssteuerungsprobleme zu lösen. Wenn Sie zwei Unternehmen gleichzeitig interviewen möchten:
function interview() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('success') } else { reject(new Error('fail')) } }) }) } promise .all([interview(), interview()]) .then(() => { console.log('smile') }) // 如果有一家公司rejected,就catch .catch(() => { console.log('cry') })
async/await
sync/await Was genau ist:
console.log(async function() { return 4 }) console.log(function() { return new Promise((resolve, reject) => { resolve(4) }) })
Die gedruckten Ergebnisse sind die gleichen, das heißt, async/await ist nur der syntaktische Zucker des Versprechens. Wir wissen, dass Try Catch Fehler erfasst,
vom Aufrufstapel abhängt und nur Fehler oberhalb des Aufrufstapels erfassen kann. Wenn Sie jedoch „await“ verwenden, können Sie Fehler in allen Funktionen im Aufrufstapel abfangen. Auch wenn der Fehler in der Aufrufliste einer anderen Ereignisschleife, z. B. setTimeout, ausgegeben wird. Nach der Transformation des Interviewcodes können Sie sehen, dass der Code deutlich optimiert ist.try { await interview(1) await interview(2) await interview(2) } catch(e => { console.log(e) })
await Promise.all([interview(1), interview(2)])
dieser C++-Bibliothek bereitgestellt werden. 
代码演示:
const eventloop = {
queue: [],
loop() {
while(this.queue.length) {
const callback = this.queue.shift()
callback()
}
setTimeout(this.loop.bind(this), 50)
},
add(callback) {
this.queue.push(callback)
}
}
eventloop.loop()
setTimeout(() => {
eventloop.add(() => {
console.log('1')
})
}, 500)
setTimeout(() => {
eventloop.add(() => {
console.log('2')
})
}, 800)
Nach dem Login kopieren
setTimeout(this.loop.bind(this), 50)
保证了50ms就会去看队列中是否有回调,如果有就去执行。这样就形成了一个事件循环。
当然实际的事件要复杂的多,队列也不止一个,比如有一个文件操作对列,一个时间对列。
const eventloop = {
queue: [],
fsQueue: [],
timerQueue: [],
loop() {
while(this.queue.length) {
const callback = this.queue.shift()
callback()
}
this.fsQueue.forEach(callback => {
if (done) {
callback()
}
})
setTimeout(this.loop.bind(this), 50)
},
add(callback) {
this.queue.push(callback)
}
}
Nach dem Login kopieren
总结
首先我们弄清楚了什么是非阻塞I/O,即遇到I/O立刻跳过执行后面的任务,不会等待I/O的结果。当I/O处理好了之后就会调用我们注册的事件处理函数,这就叫事件驱动。实现事件驱动就必须要用异步编程,异步编程是nodejs中最重要的环节,它从回调函数到promise,最后到async/await(使用同步的方法写异步逻辑)。
更多node相关知识,请访问:nodejs 教程!
const eventloop = { queue: [], loop() { while(this.queue.length) { const callback = this.queue.shift() callback() } setTimeout(this.loop.bind(this), 50) }, add(callback) { this.queue.push(callback) } } eventloop.loop() setTimeout(() => { eventloop.add(() => { console.log('1') }) }, 500) setTimeout(() => { eventloop.add(() => { console.log('2') }) }, 800)
setTimeout(this.loop.bind(this), 50)
保证了50ms就会去看队列中是否有回调,如果有就去执行。这样就形成了一个事件循环。const eventloop = { queue: [], fsQueue: [], timerQueue: [], loop() { while(this.queue.length) { const callback = this.queue.shift() callback() } this.fsQueue.forEach(callback => { if (done) { callback() } }) setTimeout(this.loop.bind(this), 50) }, add(callback) { this.queue.push(callback) } }
Das obige ist der detaillierte Inhalt vonZusammenfassung und Weitergabe, um mehrere Schlüsselknoten von NodeJS zu verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Node.js ist eine serverseitige JavaScript-Laufzeitumgebung, während Vue.js ein clientseitiges JavaScript-Framework zum Erstellen interaktiver Benutzeroberflächen ist. Node.js wird für die serverseitige Entwicklung verwendet, beispielsweise für die Entwicklung von Back-End-Service-APIs und die Datenverarbeitung, während Vue.js für die clientseitige Entwicklung verwendet wird, beispielsweise für Single-Page-Anwendungen und reaktionsfähige Benutzeroberflächen.

Node.js kann als Backend-Framework verwendet werden, da es Funktionen wie hohe Leistung, Skalierbarkeit, plattformübergreifende Unterstützung, ein umfangreiches Ökosystem und einfache Entwicklung bietet.

Um eine Verbindung zu einer MySQL-Datenbank herzustellen, müssen Sie die folgenden Schritte ausführen: Installieren Sie den MySQL2-Treiber. Verwenden Sie mysql2.createConnection(), um ein Verbindungsobjekt zu erstellen, das die Hostadresse, den Port, den Benutzernamen, das Passwort und den Datenbanknamen enthält. Verwenden Sie „connection.query()“, um Abfragen durchzuführen. Verwenden Sie abschließend Connection.end(), um die Verbindung zu beenden.

Die folgenden globalen Variablen sind in Node.js vorhanden: Globales Objekt: global Kernmodul: Prozess, Konsole, erforderlich Laufzeitumgebungsvariablen: __dirname, __filename, __line, __column Konstanten: undefiniert, null, NaN, Infinity, -Infinity

Es gibt zwei npm-bezogene Dateien im Node.js-Installationsverzeichnis: npm und npm.cmd. Die Unterschiede sind wie folgt: unterschiedliche Erweiterungen: npm ist eine ausführbare Datei und npm.cmd ist eine Befehlsfensterverknüpfung. Windows-Benutzer: npm.cmd kann über die Eingabeaufforderung verwendet werden, npm kann nur über die Befehlszeile ausgeführt werden. Kompatibilität: npm.cmd ist spezifisch für Windows-Systeme, npm ist plattformübergreifend verfügbar. Nutzungsempfehlungen: Windows-Benutzer verwenden npm.cmd, andere Betriebssysteme verwenden npm.

Die Hauptunterschiede zwischen Node.js und Java sind Design und Funktionen: Ereignisgesteuert vs. Thread-gesteuert: Node.js ist ereignisgesteuert und Java ist Thread-gesteuert. Single-Threaded vs. Multi-Threaded: Node.js verwendet eine Single-Threaded-Ereignisschleife und Java verwendet eine Multithread-Architektur. Laufzeitumgebung: Node.js läuft auf der V8-JavaScript-Engine, während Java auf der JVM läuft. Syntax: Node.js verwendet JavaScript-Syntax, während Java Java-Syntax verwendet. Zweck: Node.js eignet sich für I/O-intensive Aufgaben, während Java für große Unternehmensanwendungen geeignet ist.

Ja, Node.js ist eine Backend-Entwicklungssprache. Es wird für die Back-End-Entwicklung verwendet, einschließlich der Handhabung serverseitiger Geschäftslogik, der Verwaltung von Datenbankverbindungen und der Bereitstellung von APIs.

Serverbereitstellungsschritte für ein Node.js-Projekt: Bereiten Sie die Bereitstellungsumgebung vor: Erhalten Sie Serverzugriff, installieren Sie Node.js, richten Sie ein Git-Repository ein. Erstellen Sie die Anwendung: Verwenden Sie npm run build, um bereitstellbaren Code und Abhängigkeiten zu generieren. Code auf den Server hochladen: über Git oder File Transfer Protocol. Abhängigkeiten installieren: Stellen Sie eine SSH-Verbindung zum Server her und installieren Sie Anwendungsabhängigkeiten mit npm install. Starten Sie die Anwendung: Verwenden Sie einen Befehl wie node index.js, um die Anwendung zu starten, oder verwenden Sie einen Prozessmanager wie pm2. Konfigurieren Sie einen Reverse-Proxy (optional): Verwenden Sie einen Reverse-Proxy wie Nginx oder Apache, um den Datenverkehr an Ihre Anwendung weiterzuleiten
