
Daten binär
Alle Inhalte im Computer: Text, Zahlen, Bilder, Audio und Video werden schließlich durch Binärdaten dargestellt,
z. B. Zeichenfolgen. Wir zeigen diese Inhalte normalerweise den Benutzern an JS
aber Sie denken vielleicht, dass JS es ist
Tatsächlichwerden Bilder
JS oder HTML verarbeitet. Es ist nur dafür verantwortlich, dem Browser die Adresse des Bildesist jedoch anders.
GBK utf-8sharp , die für das Lesen von Bildern oder Buffer eingehender Bilder und deren anschließende Verarbeitung verantwortlich ist.Node eine lange Verbindung über TCP hergestellt und ein Byte übertragen Wir müssen die Daten in Bytes konvertieren, bevor wir sie übergeben, und die Größe der übertragenen Bytes muss bekannt sein (der Client muss anhand der Größe beurteilen, wie viel Inhalt gelesen werden soll).Puffer und Binärdaten
werden wir finden Bei der Front-End-Entwicklung ist es normalerweise selten, mit Binärdaten umzugehen. Um jedoch viele Funktionen auf der Serverseite zu implementieren, müssen wir die Binärdaten direkt bedienen,
um Entwicklern die Ausführung weiterer Funktionen zu erleichtern Node stellt uns eine Klasse namens Buffer zur Verfügung, die global ist. Wie
bereits erwähnt, werden Binärdaten im Buffer gespeichert. Wie werden sie also gespeichert?
8 -Bit-Binärdaten speichern: 00000000 , was genau einem Byte entspricht.
byte1 byte = 8 bit , 1kb = 1024 byte , 1M = 1024kb , 1 G = 1024 Mint Typ in vielen Programmiersprachen 4 Bytes und der long -Typ 8 Bytes.TCPRGB -Wert jeweils 255 , sodassder Puffer und der Zeichenfolgenpuffer
im WesentlichenBuffer einem Byte im Computer gespeichert werden entspricht einem Array von Bytes. Jedes Element im Array hat eine Größe.
Wenn wir eine Zeichenfolge in einen Puffer einfügen möchten, wie läuft das ab?
buffer .const message = 'Hello'. // Verwenden Sie das Schlüsselwort new, um eine Pufferinstanz zu erstellen, aber diese Erstellungsmethode ist abgelaufen const buffer = new Buffer(message) console.log(buffer); // <Puffer 48 65 6c 6c 6f> console.log(buffer.toString()); // Hallo
chinesische String-Kodierung und -Dekodierung.
buffer ist utf-8 . Im folgenden Code verwendet die Buffer Klasse also die utf-8-Kodierung Wir verwenden auch UTF-8, um unsere Zeichenfolgen zu dekodieren.3 Byte-Binärkodierungconst message = „Hallo“. // Verwenden Sie Buffer.from, um unseren String zu dekodieren const buffer = Buffer.from(message) console.log(buffer); // <Puffer e4 bd a0 e5 a5 bd e5 95 8a> // Es gibt eine toString-Methode in der Pufferinstanz, die die Kodierung dekodieren kann console.log(buffer.toString()); // 'Hallo'
, was passiert, wenn Kodierung und Dekodierung unterschiedliche Formen der Kodierungsergebnisse verwenden?
const message = 'Hello' const buffer = Buffer.from(message, 'utf16le') console.log(buffer); // <Puffer 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
Andere Möglichkeiten, Puffer
buffer erstellen. Hier können wir Buffer durch alloc
erstellen Jedes Bit wird geändert.
// Dies kann die Anzahl der Ziffern angeben Wenn hier beispielsweise 8 übergeben wird, enthält der erstellte Puffer 8 Elemente und die jedem Element entsprechende Binärzahl ist 0. const buffer = Buffer.alloc(8) console.log(buffer); // <Puffer 00 00 00 00 00 00 00 00> // Wenn der Wert einer Dezimalzahl zugewiesen ist, hilft uns der Puffer, ihn in eine Hexadezimalzahl umzuwandeln und ihn dann an den entsprechenden Speicherort zu schreiben buffer[0] = 88 // In js wird alles, was mit 0x beginnt, als hexadezimale Zahl buffer[1] = 0x88 dargestellt console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>
Puffer- und Dateioperationen
1. Wenn die Textdatei
buffer wird direkt zurückgegeben , das ist das utf-8 codierte Binärzahlergebnis.const fs = require('fs')
fs.readFile('./a.txt', (err, data) => {
console.log(data); // <Puffer e5 93 88 e5 93 88>
}) const fs = require('fs') abrufen.
// Kodierung gibt die zum Dekodieren verwendete Zeichenkodierung an, und die Kodierung ist standardmäßig utf-8
fs.readFile('./a.txt', { Kodierung: 'utf-8' }, (err, data) => {
console.log(data); // Haha}) const fs = require('fs')
// Die Kodierung verwendet die Zeichenkodierung utf16le und die Dekodierung das Format utf-8. Es muss sein, dass die Dekodierung nicht korrekt ist fs.readFile('./a.txt', {kodierung: 'utf16le' }, (err , Daten) => {
console.log(data); // Fehler })
// Der obige Code ähnelt dem folgenden Code const msg = 'Haha'
const buffer = Buffer.from(msg, 'utf-8')
console.log(buffer.toString('utf16le')); // 2. Die Bilddatei
kopiert den Zweck des Kopierens des Bildes.
encoding an, da es sich um eine Zeichencodierung handeltvon
fs.readFile('./logo.png', (err, data) => {
console.log(data); // Was gedruckt wird, ist die Binärkodierung, die der Bilddatei entspricht // Wir können die Bildkodierung auch in eine andere Datei schreiben, was dem Kopieren des Bildes entspricht fs.writeFile(' ./bar .png', Daten, err => {
console.log(err);
})
}) sharp -Bibliothek verwenden.const sharp = require('sharp')
// Das Bild „logo.png“ auf 200 x 300 zuschneiden und in die Datei „bax.png“ kopieren ('./logo.png')
.resize(200, 300)
.toFile('./bax.png', (err, info) => {
console.log(err);
})
// Sie können die Bilddatei auch zuerst in einen Puffer konvertieren und dann in die Datei schreiben. Sie können das Bild auch scharf('./logo.png') kopieren.
.resize(300, 300)
.toBuffer()
.then(data => {
fs.writeFile('./baa.png', data, err => {
console.log(err);
})
}) Puffererstellungsprozess
Buffer nicht häufig Speicher vom Betriebssystem. Standardmäßig wird zunächst ein Speicher von 8 * 1024 Bytes, also 8kb ,Was ist eine Ereignisschleife?
Was ist die Ereignisschleife?
JS das wir schreiben, und dem Browser oder Node .JS Code, den wir schreiben, und den Browser-API-Aufrufen ( setTimeout , AJAX ,监听事件usw.). ) Bridges kommunizieren über Callback-Funktionen.file system , networ usw.). Bridges kommunizieren auch über Callback-Funktionen.
Prozess und Thread
Prozess und Thread sind zwei Konzepte im Betriebssystem:
process ): Das Programm, das der Computer ausgeführt hat.thread ): Die kleinste Einheit, mit der das Betriebssystem den Berechnungsplan ausführen kann, sodass CPU direkt arbeiten kannsehr abstrakt klingt, intuitiv erklären:
zu erklären
ausführen
(während sie Musik hören und Code schreiben). , und Überprüfung von Informationen) gleichzeitig funktionieren?

CPU sehr hoch ist und sie schnell zwischen mehreren Prozessen wechseln kann.
Browser und JavaScript
Wir sagen oft, dass JavaScript Single-Threaded ist, aber der JS-Thread sollte einen eigenen Containerprozess haben Node
Ist der Browser oder Node-Browser ein Prozess?
tab öffnen, wird ein neuer Prozess gestartet, um zu verhindern, dass eine Seite hängen bleibt und der gesamte Browser nicht mehrJS
JS ausführen kannJavaScript-Ausführungsfunktion
erst dann ausgeführt wird, wenn sie in den Funktionsaufrufstapel verschoben wird. Analysieren wir den Ausführungsprozess der Code-
Konstante = „Hallo Welt“.
console.log(Nachricht);
Funktion sum(num1, num2) {
Gibt Nummer1 + Nummer2 zurück
}
Funktion foo() {
const result = sum(20, 30)
console.log(result);
}
foo() main ausgeführt angesehen werdenmessage definierenlog ausführen Die Funktion wird in den Funktionsaufrufstapel eingefügt. Öffnen Sie nach der Ausführung den Stapelfoo sum während der Ausführung aufgerufen werdenjs Code wird ausgeführt und die Hauptfunktion wird ausder Ereignisschleife des Browsers
entfernt. Was passiert, wenn während der Ausführung des JS -Codes asynchrone Vorgänge auftreten?
setTimeout -Funktionsaufruf einfügenAnschließend wird die Funktion an die setTimeout-Funktion übergeben (wir nennen es timer -Funktion), wann wird es ausgeführt?
web api Funktion im Voraus. Die Timer-Funktion wird zu einer Ereigniswarteschlange hinzugefügt undWarum blockiert setTimeout nicht die Ausführung des Codes,
Dies liegt daran, dass der Browser eine sehr, sehr wichtige Sache verwaltet: Der Ereignisschleifenbrowser
hilft uns auf irgendeine Weise, die Rückruffunktion in setTimeout zu speichern. Die häufigere Methode besteht darin, sie in einem rot-schwarzen Baum zu speichern
und zu warten, bis setTimeout geplant ist Sobald die Timer-Zeit erreicht ist, wird unsere Timer-Callback-Funktion aus dem gespeicherten Ort entfernt und in die Ereigniswarteschlange gestellt.
Sobald die Ereignisschleife feststellt, dass sich etwas in unserer Warteschlange befindet und der aktuelle Funktionsaufrufstapel leer ist, wird Folgendes angezeigt:
natürlich
erst in den Stapel verschoben, wenn die vorherige Funktion in der Warteschlange herausspringt).
, Es darf nur ein Ereignis vorliegen. Während eines bestimmten Vorgangs klickt der Benutzer möglicherweise auf den Klick auf diese Schaltfläche, was einer Rückruffunktion entspricht werden auch zu unserer Warteschlange hinzugefügt. Die Ausführungsreihenfolge basiert auf der Reihenfolge, in der sie sich in der Ereigniswarteschlange befinden. Es gibt auch eine Zusammenfassung der Rückrufe, die wir ajax Anfragen an die Ereigniswarteschlange senden
: Tatsächlich ist die Ereignisschleife eine sehr einfache Sache. Das bedeutet, dass der Rückruf gespeichert wird, wenn er in einer bestimmten Situation ausgeführt werden muss im Voraus wird in die Ereigniswarteschlange gestopft, und die Ereignisschleife nimmt es heraus und legt es in den Funktionsaufrufstapel.

Makroaufgaben und Mikroaufgaben
verwalten jedoch nicht nur eine Warteschlange. Tatsächlich gibt es zwei Warteschlangen, und die Ausführung von Aufgaben in der Warteschlange muss warten,
macrotask queueajaxsetTimeout , setInterval , DOM -Überwachung, UI Rendering und anderemicrotask queue ): Promise 's then Rückruf, Mutation Observer API , queueMicrotask() usw.Welche Priorität haben also die beiden Warteschlangen in der Ereignisschleife?
main script wird zuerst ausgeführt (der geschriebene Skriptcode der obersten Ebene)..
Testpunkte: main stcipt , setTimeout , Promise , then , queueMicrotask
setTimeout(() => {
console.log('set1');4
neues Versprechen(resolve => {
lösen()
}).then(resolve => {
neues Versprechen(resolve => {
lösen()
}).then(() => {
console.log('then4');
})
console.log('then2');
})
})
neues Versprechen(resolve => {
console.log('pr1');
lösen()
}).then(() => {
console.log('then1');
})
setTimeout(() => {
console.log('set2');
})
console.log(2);
queueMicrotask(() => {
console.log('queueMicrotask');
})
neues Versprechen(resolve => {
lösen()
}).then(() => {
console.log('then3');
})
// pr1
// 2
//dann1
//queueMicrotask
//dann3
// set1
//dann2
//dann4
// set2 setTimeout wird sofort in den Funktionsaufrufstapel verschoben und sofort nach der Ausführung aus dem Stapel entfernt timer
Die an die Promise -Klasse übergebene Funktion wird sofort ausgeführt. Da es sich nicht um eine Rückruffunktion handelt, wird pr1 ausgegeben. Da die resolve ausgeführt wird, ändert sich der Status des Versprechens sofort in fulfilled , sodass die entsprechende then ausgeführt wird in die Mikrotask-Warteschlange gestellt werden und
eine setTimeout-Funktion erneut angetroffen wird. Wenn der Stapel geöffnet wird, wird seine Timer-Funktion in die Makro-Task-Warteschlange gestellt
, nachdem die Funktion auf console.log 2 geschoben wurde wird ausgedruckt und dann herausgesprungen.
Hier wird eine Funktion an queueMicrotask gebunden und nach dem Betreten der Mikrotask-Warteschlange
eine neue Promise-Anweisung angetroffen, die jedoch den Versprechensstatus sofort in „erfüllt“ ändert, also den Rückruf Die der Funktion then entsprechende Funktion wurde ebenfalls in die Mikrotask-Warteschlange gestellt.
Da der Synchronisationsskriptcode ausgeführt wurde, werden nun die mit der Mikrotask-Warteschlange und der Makroaufgabe konkurrierenden Aufgaben zu Beginn der Schleife in die Warteschlange gestellt Hinweis: Die Priorität von Mikroaufgaben ist höher als die von Makroaufgaben. Sie müssen sie jedes Mal lesen, wenn Sie eine Makroaufgabe ausführen möchten Es ist nicht leer, Sie müssen zuerst die Aufgabe der Mikrotask-Warteschlange ausführen,
um then1 zu drucken, die zweite Mikrotask, um queueMicrotask zu drucken, und die dritte Mikrotask, um then3 zu drucken. Beginnen Sie mit der Ausführung der Makroaufgabe.
Sie druckt zunächst set1 und führt dann eine new promise -Anweisung aus. Anschließend wird der Rückruf in die Mikrotask-Warteschlange gestellt Die Warteschlange ist nicht leer, daher muss eine Mikrotask-Warteschlange mit höherer Priorität ausgeführt werden, was der sofortigen Ausführung des Then-Rückrufs entspricht. Es handelt sich um dieselbe neue Promise-Anweisung, und der entsprechende Then-Swap wird in die Mikrotask-Warteschlange gestellt. Beachten Sie, dass nach der neuen Promise-Anweisung eine console vorhanden ist. Diese Funktion wird unmittelbar nach der Ausführung der neuen Promise-Anweisung ausgeführt, then2 then4 . Bisher ist die Mikrotask-Warteschlange leer und die Makrotask-Warteschlange kann weiterhin ausgeführt werden
, sodass der nächste Makrotask- set2 gedruckt wird. Nach der Ausführung des Makrotasks
lautet das Druckergebnis des gesamten Codes: pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
Interviewfragen <2>
Testpunkte: main script , setTimeout , Promise , then , queueMicrotask , await , async
Wissensergänzung: async, waiting ist ein Syntaxzucker Für Promise
new Promise((resolve,rejcet) => { 函数执行}) eingeschlossen istthen(res => {函数执行}) in der vorherigenasynchronen Promise-Funktion async1() {
console.log('async1 start');
warte auf async2()
console.log('async1 end');
}
asynchrone Funktion async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0)
async1()
neues Versprechen(resolve => {
console.log('promise1');
lösen()
}).then(() => {
console.log('promise2');
})
console.log('script end');
// Skriptstart
// async1 start
// async2
// versprechen1
// Skriptende
// async1 end
// versprechen2
// setTimeout ist eine Funktionsdefinition am Anfang und muss zur Ausführung nicht in den Funktionsaufrufstapel verschoben werden, bis die erste console gefunden wird. Führen Sie nach dem Pushen des Stapels das script start aus und entfernen Sie es dann Stapel,
um auf die erste setTimeout -Funktion zu stoßen, die dem entspricht timer wird in die Makro-Task-Warteschlange gestellt
und die async1-Funktion wird ausgeführt. Zuerst wird async1 start gedruckt und dann wird die async2 -Funktion nach await -Anweisung ausgeführt. Denn wie bereits erwähnt, wird die Funktion nach dem Schlüsselwort „await“ als new Promise wird sofort ausgeführt, sodass async2 ausgedruckt wird, der Code nach der „await“-Anweisung jedoch gleichbedeutend mit dem Einfügen in „then“ ist Rückruf, das heißt, console.log('async1 end') Diese Codezeile wird in die Mikrotask-Warteschlange gestellt
und der Code wird weiterhin ausgeführt. Es trifft auf eine neue Promise-Anweisung, sodass promise1 sofort gedruckt wird
,
um
script end letzte Konsolenfunktion zum Drucken auszuführen. Die Ereignisschleife wird zur Ausführung von Aufgaben in die Makrotask- und Mikrotask-Warteschlangen weitergeleitet
Die der ersten Mikrotask-Warteschlange entsprechende Druckanweisung wird ausgeführt, was bedeutet, dass async1 end gedruckt wird und dann promise2 gedruckt wird. Zu diesem Zeitpunkt ist die Mikrotask-Warteschlange leer und die Aufgaben in der Makrotask-Warteschlange werden gestartet
ausgeführt
und die endgültige Drucksequenz lautet: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout