Die Fähigkeit, Node zu verstehen, bleibt eine wichtige Fähigkeit für jeden Frontend-Entwickler. Deno ist als eine weitere Möglichkeit, JavaScript außerhalb des Browsers auszuführen, aufgetaucht, aber das riesige Ökosystem an Tools und Software, das mit Node erstellt wurde, bedeutet, dass es nicht so bald verschwinden wird.
Wenn Sie hauptsächlich JavaScript geschrieben haben, das im Browser ausgeführt wird, und mehr über die serverseitige Seite erfahren möchten, werden Ihnen viele Artikel sagen, dass Node.js eine großartige Möglichkeit ist, serverseitigen Code zu schreiben und Ihre JavaScript-Erfahrung zu nutzen.
Ich stimme zu, aber es gibt viele Herausforderungen beim Einstieg in Node.js, auch wenn Sie erfahren darin sind, clientseitiges JavaScript zu schreiben. Dieser Artikel geht davon aus, dass Sie Node installiert haben und es zum Erstellen von Frontend-Apps verwendet haben, aber Ihre eigenen APIs und Tools mit Node schreiben möchten.
Für eine Anfängererklärung von Node und npm können Sie sich Jamie Corkhills Beitrag „Getting Started With Node“ auf Smashing Magazine ansehen.
Asynchrones JavaScript
Wir müssen im Browser nicht viel asynchronen Code schreiben. Die häufigste Verwendung von asynchronem Code im Browser ist das Abrufen von Daten von einer API mit fetch (oder XMLHttpRequest, wenn Sie altmodisch sind). Andere Verwendungen von asynchronem Code können die Verwendung von setInterval, setTimeout oder die Reaktion auf Benutzerereignisse umfassen, aber wir können mit JavaScript-UI ziemlich weit kommen, ohne Genies für asynchrones JavaScript zu sein.
Wenn Sie Node verwenden, werden Sie fast *immer* asynchronen Code schreiben. Von Anfang an wurde Node entwickelt, um eine Single-Thread-Event-Schleife mit asynchronen Callbacks zu nutzen. Das Node-Team hat 2011 darüber gebloggt, wie "Node.js von Grund auf einen asynchronen Programmierstil fördert". In Ryans Dahls Vortrag zur Ankündigung von Node.js im Jahr 2009 spricht er über die Leistungsvorteile der Konzentration auf asynchrones JavaScript.
Der asynchrone First-Style ist mit ein Grund, warum Node gegenüber anderen Versuchen zur Implementierung von serverseitigem JavaScript wie Netscapes Anwendungsservern oder Narwhal an Popularität gewonnen hat. Die erzwungene Schreibweise von asynchronem JavaScript kann jedoch zu Reibungen führen, wenn Sie nicht darauf vorbereitet sind.
Einrichtung eines Beispiels
Nehmen wir an, wir entwickeln eine Quiz-App. Wir werden Benutzern erlauben, Quizze aus Multiple-Choice-Fragen zu erstellen, um das Wissen ihrer Freunde zu testen. Eine vollständigere Version dessen, was wir bauen werden, finden Sie in diesem GitHub-Repo. Sie können auch das gesamte Frontend und Backend klonen, um zu sehen, wie alles zusammenpasst, oder Sie können sich dieses CodeSandbox ansehen (führen Sie npm run start aus, um es zu starten) und sich ein Bild davon machen, was wir dort machen.

Die Quizze in unserer App bestehen aus einer Reihe von Fragen, und jede dieser Fragen hat eine Anzahl von Antwortmöglichkeiten, von denen nur eine richtig ist.
Wir können diese Daten in einer SQLite-Datenbank speichern. Unsere Datenbank wird enthalten:
- Eine Tabelle für Quizze mit zwei Spalten
- eine ganzzahlige ID
- ein Texttitel
- Eine Tabelle für Fragen mit drei Spalten
- eine ganzzahlige ID
- ein Fragetext
- Eine ganzzahlige Referenz, die mit der ID des Quiz übereinstimmt, zu dem jede Frage gehört
- Eine Tabelle für Antworten mit vier Spalten
- eine ganzzahlige ID
- ein Fragetext
- ob die Antwort richtig ist oder nicht
- eine ganzzahlige Referenz, die mit der ID der Frage übereinstimmt, zu der jede Antwort gehört
SQLite hat keinen booleschen Datentyp. Daher können wir, ob eine Antwort richtig ist, in einer Ganzzahl speichern, wobei 0 falsch und 1 wahr ist.
Zuerst müssen wir npm initialisieren und das sqlite3 npm-Paket von der Kommandozeile aus installieren.
npm init -y
npm install sqlite3
Dadurch wird eine Datei package.json erstellt. Bearbeiten wir sie und fügen Sie hinzu:
"type":"module"
zum obersten JSON-Objekt. Dies ermöglicht uns die Verwendung moderner ES6-Modulsyntax. Jetzt können wir ein Node-Skript erstellen, um unsere Tabellen einzurichten. Nennen wir unser Skript migrate.js.
// migrate.js
import sqlite3 from "sqlite3";
let db = new sqlite3.Database("quiz.db");
db.serialize(function () {
// Setting up our tables:
db.run("CREATE TABLE quiz (quizid INTEGER PRIMARY KEY, title TEXT)");
db.run("CREATE TABLE question (questionid INTEGER PRIMARY KEY, body TEXT, questionquiz INTEGER, FOREIGN KEY(questionquiz) REFERENCES quiz(quizid))");
db.run("CREATE TABLE answer (answerid INTEGER PRIMARY KEY, body TEXT, iscorrect INTEGER, answerquestion INTEGER, FOREIGN KEY(answerquestion) REFERENCES question(questionid))");
// Create a quiz with an id of 0 and a title "my quiz"
db.run("INSERT INTO quiz VALUES(0,\"my quiz\")");
// Create a question with an id of 0, a question body
// and a link to the quiz using the id 0
db.run("INSERT INTO question VALUES(0,\"What is the capital of France?\", 0)");
// Create four answers with unique ids, answer bodies, an integer for whether
// they're correct or not, and a link to the first question using the id 0
db.run("INSERT INTO answer VALUES(0,\"Madrid\",0, 0)");
db.run("INSERT INTO answer VALUES(1,\"Paris\",1, 0)");
db.run("INSERT INTO answer VALUES(2,\"London\",0, 0)");
db.run("INSERT INTO answer VALUES(3,\"Amsterdam\",0, 0)");
});
db.close();
Ich werde diesen Code nicht im Detail erklären, aber er erstellt die Tabellen, die wir zur Speicherung unserer Daten benötigen. Er erstellt auch ein Quiz, eine Frage und vier Antworten und speichert all dies in einer Datei namens quiz.db. Nachdem Sie diese Datei gespeichert haben, können wir unser Skript mit diesem Befehl von der Kommandozeile aus ausführen.
node migrate.js
Wenn Sie möchten, können Sie die Datenbankdatei mit einem Tool wie DB Browser for SQLite öffnen, um zu überprüfen, ob die Daten erstellt wurden.
Ändern der Art und Weise, wie Sie JavaScript schreiben
Schreiben wir Code, um die von uns erstellten Daten abzufragen.
Erstellen Sie eine neue Datei und nennen Sie sie index.js. Um auf unsere Datenbank zuzugreifen, können wir sqlite3 importieren, eine neue sqlite3.Database erstellen und den Pfad zur Datenbankdatei als Argument übergeben. Auf diesem Datenbankobjekt können wir die Funktion get aufrufen, indem wir eine SQL-Zeichenfolge zum Auswählen unseres Quiz und eine Callback-Funktion übergeben, die das Ergebnis protokolliert.
// index.js
import sqlite3 from "sqlite3";
let db = new sqlite3.Database("quiz.db");
db.get(`SELECT * FROM quiz WHERE quizid = 0`, (err, row) => {
if (err) {
console.error(err.message);
}
console.log(row);
db.close();
});
Wenn Sie dies ausführen, sollte { quizid: 0, title: 'my quiz' } in der Konsole ausgegeben werden.
Wie man Callbacks *nicht* verwendet
Wickeln wir diesen Code nun in eine Funktion, in der wir die ID als Argument übergeben können. Wir möchten auf jedes Quiz über seine ID zugreifen. Diese Funktion gibt das Datenbankzeilenobjekt zurück, das wir von db erhalten.
Hier beginnen wir, auf Probleme zu stoßen. Wir können das Objekt nicht einfach innerhalb des Callbacks zurückgeben, den wir an db übergeben, und weggehen. Dies ändert nicht, was unsere äußere Funktion zurückgibt. Stattdessen denken Sie vielleicht, dass wir eine Variable erstellen (nennen wir sie result) in der äußeren Funktion und diese Variable im Callback neu zuweisen. Hier ist, wie wir es versuchen könnten:
// index.js
// Be warned! This code contains BUGS
import sqlite3 from "sqlite3";
function getQuiz(id) {
let db = new sqlite3.Database("quiz.db");
let result;
db.get(`SELECT * FROM quiz WHERE quizid = ?`, [id], (err, row) => {
if (err) {
return console.error(err.message);
}
db.close();
result = row;
});
return result;
}
console.log(getQuiz(0));
Wenn Sie diesen Code ausführen, wird in der Konsolenausgabe undefined ausgegeben! Was ist passiert?
Wir sind auf eine Diskrepanz zwischen der Art und Weise gestoßen, wie wir erwarten, dass JavaScript ausgeführt wird (von oben nach unten), und wie asynchrone Callbacks ausgeführt werden. Die Funktion getQuiz im obigen Beispiel wird wie folgt ausgeführt:
- Wir deklarieren die Variable
resultmitlet result;. Wir haben dieser Variablen nichts zugewiesen, daher ist ihr Wertundefined. - Wir rufen die Funktion
db.get()auf. Wir übergeben ihr eine SQL-Zeichenfolge, die ID und einen Callback. Aber unser Callback wird noch nicht ausgeführt! Stattdessen startet das SQLite-Paket im Hintergrund eine Aufgabe, um aus der Dateiquiz.dbzu lesen. Das Lesen aus dem Dateisystem dauert relativ lange, daher erlaubt diese API unserem Benutzercode, zur nächsten Zeile zu wechseln, während Node.js im Hintergrund von der Festplatte liest. - Unsere Funktion gibt
resultzurück. Da unser Callback noch nicht ausgeführt wurde, enthältresultimmer noch den Wertundefined. - SQLite beendet das Lesen aus dem Dateisystem und führt den von uns übergebenen Callback aus, schließt die Datenbank und weist die Zeile der Variablen
resultzu. Das Zuweisen dieser Variablen macht keinen Unterschied, da die Funktion ihr Ergebnis bereits zurückgegeben hat.
Übergabe von Callbacks
Wie können wir das beheben? Vor 2015 wäre die Lösung gewesen, Callbacks zu verwenden. Anstatt unserer Funktion nur die Quiz-ID zu übergeben, übergeben wir die Quiz-ID *und* einen Callback, der das Zeilenobjekt als Argument erhält.
So sieht das aus:
// index.js
import sqlite3 from "sqlite3";
function getQuiz(id, callback) {
let db = new sqlite3.Database("quiz.db");
db.get(`SELECT * FROM quiz WHERE quizid = ?`, [id], (err, row) => {
if (err) {
console.error(err.message);
}
else {
callback(row);
}
db.close();
});
}
getQuiz(0,(quiz)=>{
console.log(quiz);
});
Das war's. Es ist ein subtiler Unterschied und einer, der Sie zwingt, die Darstellung Ihres Benutzercodes zu ändern, aber er bedeutet, dass unsere console.log nun *nachdem* die Abfrage abgeschlossen ist, ausgeführt wird.
Callback-Hölle
Aber was ist, wenn wir mehrere aufeinanderfolgende asynchrone Aufrufe tätigen müssen? Was wäre zum Beispiel, wenn wir herausfinden wollten, zu welchem Quiz eine Antwort gehört, und wir nur die ID der Antwort hätten?
Zuerst refaktoriere ich getQuiz zu einer allgemeineren Funktion get, damit wir die Tabelle und die Spalte zum Abfragen sowie die ID übergeben können.
Leider können wir die (sichereren) SQL-Parameter nicht zur Parametrisierung des Tabellennamens verwenden, daher wechseln wir stattdessen zur Verwendung einer Vorlagenzeichenfolge. In Produktionscode müssten Sie diese Zeichenfolge bereinigen, um SQL-Injection zu verhindern.
function get(params, callback) {
// In production these strings should be scrubbed to prevent SQL injection
const { table, column, value } = params;
let db = new sqlite3.Database("quiz.db");
db.get(`SELECT * FROM ${table} WHERE ${column} = ${value}`, (err, row) => {
callback(err, row);
db.close();
});
}
Ein weiteres Problem ist, dass es beim Lesen aus der Datenbank zu einem Fehler kommen kann. Unser Benutzercode muss wissen, ob jede Datenbankabfrage einen Fehler hatte. Andernfalls sollte er nicht mit der Abfrage der Daten fortfahren. Wir verwenden die Node.js-Konvention, ein Fehlerobjekt als erstes Argument unseres Callbacks zu übergeben. Dann können wir prüfen, ob ein Fehler vorliegt, bevor wir fortfahren.
Nehmen wir unsere Antwort mit der id 2 und prüfen, zu welchem Quiz sie gehört. Hier ist, wie wir das mit Callbacks tun können:
// index.js
import sqlite3 from "sqlite3";
function get(params, callback) {
// In production these strings should be scrubbed to prevent SQL injection
const { table, column, value } = params;
let db = new sqlite3.Database("quiz.db");
db.get(`SELECT * FROM ${table} WHERE ${column} = ${value}`, (err, row) => {
callback(err, row);
db.close();
});
}
get({ table: "answer", column: "answerid", value: 2 }, (err, answer) => {
if (err) {
console.log(err);
} else {
get(
{ table: "question", column: "questionid", value: answer.answerquestion },
(err, question) => {
if (err) {
console.log(err);
} else {
get(
{ table: "quiz", column: "quizid", value: question.questionquiz },
(err, quiz) => {
if (err) {
console.log(err);
} else {
// This is the quiz our answer belongs to
console.log(quiz);
}
}
);
}
}
);
}
});
Wow, das ist viel Verschachtelung! Jedes Mal, wenn wir eine Antwort von der Datenbank erhalten, müssen wir zwei Verschachtelungsebenen hinzufügen – eine zur Fehlerprüfung und eine für den nächsten Callback. Wenn wir immer mehr asynchrone Aufrufe verketten, wird unser Code tiefer und tiefer.
Wir könnten dies teilweise verhindern, indem wir benannte Funktionen anstelle von anonymen Funktionen verwenden, was die Verschachtelung geringer halten würde, aber unseren Code weniger prägnant machen würde. Wir müssten uns auch Namen für all diese Zwischenfunktionen ausdenken. Glücklicherweise kamen Promises im Jahr 2015 in Node, um bei verketteten asynchronen Aufrufen wie diesem zu helfen.
Promises
Das Umschließen von asynchronen Aufgaben mit Promises ermöglicht es Ihnen, viel von der Verschachtelung im vorherigen Beispiel zu vermeiden. Anstatt immer tiefer verschachtelte Callbacks zu haben, können wir einen Callback an die then-Funktion eines Promise übergeben.
Zuerst ändern wir unsere get-Funktion so, dass sie die Datenbankabfrage mit einem Promise umschließt.
// index.js
import sqlite3 from "sqlite3";
function get(params) {
// In production these strings should be scrubbed to prevent SQL injection
const { table, column, value } = params;
let db = new sqlite3.Database("quiz.db");
return new Promise(function (resolve, reject) {
db.get(`SELECT * FROM ${table} WHERE ${column} = ${value}`, (err, row) => {
if (err) {
return reject(err);
}
db.close();
resolve(row);
});
});
}
Jetzt kann unser Code zur Suche nach dem Quiz, zu dem eine Antwort gehört, wie folgt aussehen:
get({ table: "answer", column: "answerid", value: 2 })
.then((answer) => {
return get({
table: "question",
column: "questionid",
value: answer.answerquestion,
});
})
.then((question) => {
return get({
table: "quiz",
column: "quizid",
value: question.questionquiz,
});
})
.then((quiz) => {
console.log(quiz);
})
.catch((error) => {
console.log(error);
}
);
Das ist eine viel schönere Art, unseren asynchronen Code zu behandeln. Und wir müssen nicht mehr individuell Fehler für jeden Aufruf behandeln, sondern können die catch-Funktion verwenden, um alle Fehler zu behandeln, die in unserer Kette von Funktionen auftreten.
Wir müssen immer noch viele Callbacks schreiben, um das zum Laufen zu bringen. Glücklicherweise gibt es eine neuere API, die hilft! Als Node 7.6.0 veröffentlicht wurde, wurde seine JavaScript-Engine auf V8 5.5 aktualisiert, was die Möglichkeit bietet, ES2017 async/await Funktionen zu schreiben.
Async/Await
Mit async/await können wir unseren asynchronen Code fast genauso schreiben wie synchronen Code. Sarah Drasner hat einen großartigen Beitrag zur Erklärung von async/await.
Wenn Sie eine Funktion haben, die ein Promise zurückgibt, können Sie das Schlüsselwort await verwenden, bevor Sie sie aufrufen, und es verhindert, dass Ihr Code zur nächsten Zeile wechselt, bis das Promise aufgelöst ist. Da wir die Funktion get() bereits so refaktoriert haben, dass sie ein Promise zurückgibt, müssen wir nur unseren Benutzercode ändern:
async function printQuizFromAnswer() {
const answer = await get({ table: "answer", column: "answerid", value: 2 });
const question = await get({
table: "question",
column: "questionid",
value: answer.answerquestion,
});
const quiz = await get({
table: "quiz",
column: "quizid",
value: question.questionquiz,
});
console.log(quiz);
}
printQuizFromAnswer();
Das sieht unserem gewohnten Code vertrauter aus. Allein in diesem Jahr hat Node Top-Level-await veröffentlicht. Das bedeutet, wir können dieses Beispiel noch prägnanter gestalten, indem wir die Funktion printQuizFromAnswer() entfernen, die unsere get()-Funktionsaufrufe umschließt.
Jetzt haben wir prägnanten Code, der diese asynchronen Aufgaben sequenziell ausführt. Wir könnten auch andere asynchrone Funktionen (wie das Lesen von Dateien oder das Reagieren auf HTTP-Anfragen) gleichzeitig starten, während wir darauf warten, dass dieser Code ausgeführt wird. Das ist der Vorteil des gesamten asynchronen Stils.
Da es in Node so viele asynchrone Aufgaben gibt, wie z. B. das Lesen aus dem Netzwerk oder der Zugriff auf eine Datenbank oder ein Dateisystem, ist es besonders wichtig, diese Konzepte zu verstehen. Sie haben auch eine Lernkurve.
SQL optimal nutzen
Es gibt noch einen besseren Weg! Anstatt sich mit diesen asynchronen Aufrufen befassen zu müssen, um jedes Datenstück zu erhalten, könnten wir SQL verwenden, um alle benötigten Daten in einer einzigen großen Abfrage abzurufen. Das können wir mit einer SQL-JOIN-Abfrage tun.
// index.js
import sqlite3 from "sqlite3";
function quizFromAnswer(answerid, callback) {
let db = new sqlite3.Database("quiz.db");
db.get(
`SELECT *,a.body AS answerbody, ques.body AS questionbody FROM answer a
INNER JOIN question ques ON a.answerquestion=ques.questionid
INNER JOIN quiz quiz ON ques.questionquiz = quiz.quizid
WHERE a.answerid = ?;`,
[answerid],
(err, row) => {
if (err) {
console.log(err);
}
callback(err, row);
db.close();
}
);
}
quizFromAnswer(2, (e, r) => {
console.log(r);
});
Dies gibt uns alle benötigten Daten zu unserer Antwort, Frage und unserem Quiz in einem großen Objekt zurück. Wir haben auch die Spalten body für Antworten und Fragen in answerbody und questionbody umbenannt, um sie zu unterscheiden. Wie Sie sehen, kann das Auslagern von mehr Logik in die Datenbankschicht Ihre JavaScript vereinfachen (und möglicherweise die Leistung verbessern).
Wenn Sie eine relationale Datenbank wie SQLite verwenden, haben Sie eine ganze weitere Sprache zu lernen, mit vielen verschiedenen Funktionen, die Zeit und Aufwand sparen und die Leistung steigern können. Dies fügt der Liste der zu lernenden Dinge für das Schreiben von Node noch mehr hinzu.
Node APIs und Konventionen
Beim Wechsel von Browsercode zu Node.js gibt es viele neue Node-APIs zu lernen.
Alle Datenbankverbindungen und/oder Lesevorgänge aus dem Dateisystem verwenden APIs, die wir im Browser (noch) nicht haben. Wir haben auch neue APIs zum Einrichten von HTTP-Servern. Wir können Prüfungen am Betriebssystem mit dem OS-Modul durchführen und Daten mit dem Crypto-Modul verschlüsseln. Um eine HTTP-Anfrage von Node aus zu stellen (etwas, das wir im Browser ständig tun), gibt es keine fetch- oder XMLHttpRequest-Funktion. Stattdessen müssen wir das https-Modul importieren. Eine kürzlich erfolgte Änderung im Node.js-Repository zeigt jedoch, dass Fetch in Node anscheinend auf dem Weg ist! Es gibt immer noch viele Unterschiede zwischen Browser- und Node-APIs. Dies ist eines der Probleme, die Deno zu lösen versucht.
Wir müssen auch Node-Konventionen kennen, einschließlich der Datei package.json. Die meisten Frontend-Entwickler werden damit ziemlich vertraut sein, wenn sie Build-Tools verwendet haben. Wenn Sie eine Bibliothek veröffentlichen möchten, ist Ihnen der Teil, der Ihnen möglicherweise nicht vertraut ist, die Eigenschaft main in der Datei package.json. Diese Eigenschaft enthält einen Pfad, der auf den Einstiegspunkt der Bibliothek verweist.
Es gibt auch Konventionen wie "error-first callbacks": Ein Node-API nimmt einen Callback entgegen, der einen Fehler als erstes Argument und das Ergebnis als zweites Argument erhält. Dies haben Sie bereits in unserem Datenbankcode und unten bei der Verwendung der Funktion readFile gesehen.
import fs from 'fs';
fs.readFile('myfile.txt', 'utf8' , (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
Unterschiedliche Modultypen
Vorhin habe ich Sie beiläufig angewiesen, "type":"module" in Ihre package.json-Datei einzufügen, damit die Codebeispiele funktionieren. Als Node im Jahr 2009 erstellt wurde, benötigten die Entwickler ein Modulsystem, das aber in der JavaScript-Spezifikation nicht existierte. Sie erfanden Common.js-Module, um dieses Problem zu lösen. Im Jahr 2015 wurde eine Modulspezifikation in JavaScript eingeführt, was dazu führte, dass Node.js ein Modulsystem hatte, das sich von nativen JavaScript-Modulen unterschied. Nach einer herkulischen Anstrengung des Node-Teams können wir diese nativen JavaScript-Module nun in Node verwenden.
Leider bedeutet dies, dass viele Blogbeiträge und Ressourcen mit dem älteren Modulsystem geschrieben werden. Es bedeutet auch, dass viele npm-Pakete keine nativen JavaScript-Module verwenden und es manchmal Bibliotheken geben wird, die native JavaScript-Module auf inkompatible Weise verwenden!
Weitere Bedenken
Es gibt noch ein paar weitere Bedenken, über die wir beim Schreiben von Node nachdenken müssen. Wenn Sie einen Node-Server betreiben und eine fatale Ausnahme auftritt, wird der Server beendet und hört auf, auf Anfragen zu reagieren. Das bedeutet, wenn Sie einen Fehler machen, der auf einem Node-Server schlimm genug ist, ist Ihre Anwendung für alle kaputt. Dies unterscheidet sich von clientseitigem JavaScript, bei dem ein Edge-Case, der zu einem fatalen Fehler führt, von einem Benutzer nach dem anderen erlebt wird und dieser Benutzer die Option hat, die Seite neu zu laden.
Sicherheit ist etwas, worüber wir uns im Frontend bereits mit Cross-Site Scripting und Cross-Site Request Forgery Sorgen machen sollten. Aber ein Backend-Server hat eine größere Angriffsfläche mit Schwachstellen wie Brute-Force-Angriffen und SQL-Injection. Wenn Sie mit Node Informationen über Personen speichern und darauf zugreifen, haben Sie eine große Verantwortung, deren Daten zu schützen.
Fazit
Node ist eine großartige Möglichkeit, Ihre JavaScript-Fähigkeiten zum Erstellen von Servern und Kommandozeilen-Tools zu nutzen. JavaScript ist eine benutzerfreundliche Sprache, die wir gewohnt sind zu schreiben. Und Nodes asynchroner First-Nature bedeutet, dass Sie damit schnell durch gleichzeitige Aufgaben schmettern können. Aber es gibt viele neue Dinge zu lernen, wenn man anfängt. Hier sind die Ressourcen, die ich mir gewünscht hätte, bevor ich eingestiegen bin:
- Asynchrones JavaScript (MDN)
- Verständnis von Async Await (Sarah Drasner)
- Einführung in Node.js (Node.js-Dokumentation)
- Get Started With Node (Jamie Corkhill)
- Originale Node.js-Präsentation (Ryan Dahl)
- Native JavaScript-Module (Node.js-Dokumentation)
Und wenn Sie Daten in einer SQL-Datenbank speichern möchten, lesen Sie SQL-Grundlagen.
Warum haben Sie SQLite als DB verwendet, um Ihren Stack zu vervollständigen, anstatt MongoDB, wenn MongoDB die offensichtlichere Wahl für Node.JS zu sein scheint?
Hallo Mark!
Der Hauptgrund für die Wahl von SQLite für diesen Artikel war, dass Sie keinen Datenbankserver installieren müssen, um es zu verwenden. :) Sie verwenden einfach das npm-Paket und das Dateisystem. Außerdem ist es wahrscheinlich nützlich, ein wenig SQL zu kennen, auch wenn es nicht die offensichtlichste Wahl für Node.js ist.
Aber wo Sie es gerade erwähnen, vielleicht wäre dieser Artikel repräsentativer dafür, wie sich das Schreiben von Node-Code anfühlt, wenn ich MongoDB dafür verwendet hätte.