Heim > Artikel > Web-Frontend > Eine eingehende Analyse der Asynchronität in Node.js
Dieser Artikel gibt Ihnen eine detaillierte Einführung in Asynchronität in Node.js. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Über Node.js asynchron gibt es zwei Dinge, die nicht vermieden werden können: nicht blockierende E/A und Ereignisschleife. Gerade aufgrund dieser beiden Punkte kann Node.js als leistungsstark bezeichnet und in Online-Umgebungen eingesetzt werden. Lernen wir also den asynchronen Mechanismus und die Verwendung von Node.js kennen! [Empfohlenes Lernen: „nodejs-Tutorial“]
Eingabe
/Ausgabe
, a Die Input
/Output
,一个系统的输入和输出。以点菜吃饭为例子:去饭堂点菜吃饭需要排队等待,在这个过程中,阿姨每次只能接待一个人,“点菜-阿姨抖勺装菜-把饭菜给到你”这个过程中阿姨并不能接收其他人的点菜,这个就是阻塞 I/O;而去餐馆点菜吃饭,去到餐馆就可以跟服务员你要吃番茄炒蛋,服务员记下来之后交给后厨,这时候来了另一桌人就把服务员招呼过去说想吃小龙虾,也就是说,在把菜给你上上来之前服务员接收了其他人的点菜,那这个就是非阻塞型 I/O。
理解非阻塞 I/O 的要点在于
Input
/Output
的系统。那在点菜吃饭这个例子中,一个进行 Input
/Output
的系统就是点餐-后厨(阿姨)处理-上菜这样一个能让你吃上饭的系统;点餐就是 Input
,上菜就是 Output
,在这个例子中判断两者是非阻塞型还是阻塞型的关键就在于在点菜上菜这个过程中能不能接受其它的点菜上菜。就好比你点了个佛跳墙,等上菜可能就要好久了,然后来的人都是点一些简单的菜品,一分钟炒一份炒粉的那种,可能就是来来回回几波人之后都还没能给你上菜。
而 Node.js 它是用来操纵计算机的,一些如读取文件之类的操作是非常耗时的,要是不能进行其它的 I/O,那么处理效率就很会很低了,这也是 Node.js 是非阻塞型 I/O 的一个原因。
Node.js 启动的时候会初始化由 libuv 提供的事件循环,每次的事件循环都包含6个阶段,这6个阶段会在每一次的事件循环当中按照下图当中的顺序反复执行,如下图:
timers
阶段:这个阶段执行 timer
(setTimeout
、setInterval
)的回调callbacks
阶段 :处理一些上一轮循环中的少数未执行的 I/O 回调idle
,prepare
阶段 :仅 Node 内部使用poll
阶段 :获取新的 I/O 事件, 适当的条件下 Node 将阻塞在这里check
阶段 :执行 setImmediate()
的回调close callbacks
阶段:执行 socket
的 close
事件回调每个阶段都有一个先入先出的(FIFO)的用于执行回调的队列,事件循环运行到每个阶段,都会从对应的回调队列中取出回调函数去执行,直到队列当中的内容耗尽,或者执行的回调数量达到了最大。
然后事件循环就会进入下一个阶段,然后又从下一个阶段对应的队列中取出回调函数执行,这样反复直到事件循环的最后一个阶段。而事件循环也会一个一个按照循环执行,直到进程结束。
事件循环当中的6个宏队列和微队列的关系如下:微队列(microtask
)在事件循环的各个阶段之间执行,或者说在事件循环的各个阶段对应的宏队列(macrotask
Ein- und Ausgänge
Der Unterschied zwischen blockierender und nicht blockierender E/A besteht darin, ob das System während des Zeitraums von der Eingabe bis zur Ausgabe andere Eingaben empfangen kann. Nehmen Sie das Bestellen von Essen als Beispiel: Um Essen in der Kantine zu bestellen, müssen Sie in der Schlange stehen. Während dieses Vorgangs kann die Tante jeweils nur eine Person empfangen: „Essen bestellen – Tante.“ schüttelt den Löffel, um das Essen zu laden – Während die Tante „dir das Essen bringt“, kann sie die Bestellungen anderer Leute nicht annehmen. Das merkt man, wenn man in ein Restaurant geht, um Essen zu bestellen dem Kellner, dass Sie Tomaten-Rührei essen möchten, wenn Sie ins Restaurant gehen. Nachdem Sie es aufgeschrieben haben, kommen Leute von einem anderen Tisch und sagen, dass sie Flusskrebse essen möchten . Mit anderen Worten, der Kellner
nahm die Bestellungen anderer Leute entgegen, bevor er Ihnen die Gerichte servierte. Dann ist dies eine nicht blockierende E/A. Der Schlüssel zum Verständnis nicht blockierender E/A besteht darin, 🎜🎜🎜🎜ein System zu bestimmen🎜, dasEingabe
/Ausgabe
durchführt. 🎜🎜Überlegen Sie, ob während des E/A-Prozesses andere E/A-Vorgänge ausgeführt werden können🎜. 🎜Im Beispiel der Essensbestellung ist ein System, das Eingabe
/Ausgabe
ausführt, die Bestellung – verarbeitet durch die Küche (Tante) – das Servieren Ein System, mit dem Sie essen können, ist Eingabe
und das Servieren ist Ausgabe
. Bestimmen Sie in diesem Beispiel, ob die beiden nicht blockierend sind Sie können während des Bestell- und Serviervorgangs weitere Bestellungen und Gerichte annehmen. Es ist so, als würde man bei „Buddha springt über die Mauer“ lange warten, bis das Essen serviert wird. Dann bestellen die Leute, die kommen, ein paar einfache Gerichte, die Art von gebratenen Nudeln, die man darin frittieren kann Eine Minute. Vielleicht konnte ich Ihnen nach ein paar Wellen von Leuten noch kein Essen servieren. 🎜🎜Node.js wird zur Steuerung des Computers verwendet. Wenn andere E/A-Vorgänge nicht ausgeführt werden können, ist dies auch ein Grund dafür für nicht blockierende E/A. 🎜timers
-Stufe: Diese Stufe führt timer
aus ( setTimeout
, setInterval) Rückrufe🎜E/A-<code>Rückrufe
-Stufe: Behandeln Sie einige nicht ausgeführte E/As im vorherigen Zyklus. Rückruf🎜idle
, prepare Phase: wird nur intern vom Node verwendet🎜poll
Phase: neues I/O-Ereignis abrufen, Node wird hier unter geeigneten Bedingungen blockieren🎜check
-Phase: Führen Sie den Rückruf von setImmediate()
🎜close callbacks-Phase aus: Führen Sie den <code>close
-Ereignisrückruf aus of socket
🎜🎜Jede Stufe verfügt über eine First-In-First-Out-Funktion (FIFO). In Bezug auf die Warteschlange zum Ausführen von Rückrufen gilt in jeder Stufe der Ereignisschleife die Die Rückruffunktion wird aus der entsprechenden Rückrufwarteschlange entnommen und ausgeführt, bis der Inhalt in der Warteschlange erschöpft ist oder die Anzahl der ausgeführten Rückrufe das Maximum erreicht. 🎜🎜Dann tritt die Ereignisschleife in die nächste Stufe ein, und dann wird die Rückruffunktion aus der Warteschlange entsprechend der nächsten Stufe entnommen und ausgeführt, und dies wird bis zur letzten Stufe der Ereignisschleife wiederholt. Die Ereignisschleife wird ebenfalls nacheinander ausgeführt, bis der Prozess beendet ist. 🎜🎜Die Beziehung zwischen den sechs Makrowarteschlangen und Mikrowarteschlangen in der Ereignisschleife ist wie folgt: Die Mikrowarteschlange (microtask
) wird zwischen verschiedenen Phasen der Ereignisschleife oder den entsprechenden Makros in jeder Phase ausgeführt Die Ereignisschleife wird zwischen Warteschlangen ausgeführt (Makrotask
). 🎜🎜🎜🎜🎜Hier ist eine besonders verwirrende Versionsänderung: 🎜setTimeout
, setInterval
und setImmediate
) in einer Phase ausgeführt wird, eine der drei, außer E/A ), führen Sie sofort die Mikrotask-Warteschlange aus, führen Sie alle Mikrotasks in der Mikrowarteschlange aus und kehren Sie dann gerade zur Makrowarteschlange zurück, um die nächste Makrotask auszuführen. Dies setTimeout
,setInterval
和 setImmediate
三者其中之一,不包括I/O)就立刻执行微任务队列,执行完微队列当中的所有微任务再回到刚才的宏队列执行下一个宏任务。这就跟浏览器端运行一致了。callback
error-first callback
node-style callback
error
,后面的参数才是结果。// 第一个参数是错误捕获 interview(function (err, res) { if (err) { console.log('cry') return; } console.log('smile') }) function interview(callback) { setTimeout(() => { if (Math.random() > 0.2) { callback(null, 'success') } else { callback(new Error('fail')) } }, 500) }
异步流程控制:回调地狱、异步并发等问题
npm
:async.js
;可以通过 async.js
来控制异步流程thunk
:一种编程方式Promise
Promise
是承诺的意思;当前事件循环得不到的结果,但未来的事件循环会给到你结果resolved
或 rejected
就不会改变pending
:初始状态,还没得到结果的状态fulfilled
/ resolved
:成功状态rejected
:失败状态链式调用:.then
和 .catch
resolved
状态的 Promise
会回调后面的第一个 .then
rejected
状态的 Promise
会回调后面的第一个 .catch
rejected
状态且后面没有 .catch
的 Promise
,都会造成浏览器/ Node 环境的全局错误// promise的状态转换以及通过then获取内容 const promise = new Promise((resolve, reject) => { setTimeout(function () { resolve(3); // reject(new Error(4)) }, 500) }) promise.then(function (result) { console.log(result) }).catch(function (err) { console.log(err) }) setTimeout(() => { console.log(promise) }, 800)
执行 then
和 catch
会返回一个新 Promise
,该 Promise
最终状态根据 then
和 catch
的回调函数的执行结果决定
throw
,该 Promise
是 rejected
状态return
,该 Promise
是 resolved
状态return
了一个 Promise
,该 Promise
会和回调函数 return
的 Promise
状态保持一致async
/await
async function
是 Promise
的语法糖封装await
关键字可以“暂停” async function
的执行await
关键字可以以同步的写法获取 Promise
的执行结果try-catch
可以获取 await
所得到的错误(async function () { await findJob() console.log('trip') })() async function findJob() { try { // 进行三轮面试 await interview(1); await interview(2); await interview(3); console.log('smile') } catch (e) { console.log('cry at ' + e.round) } } // 进行第round轮面试 function interview(round) { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.2) { const error = new Error('failed'); error.round = round; reject(error); } else { resolve('success'); } }, 500) }) }
这是一个穿越事件循环存在的 function
。
error
,后面的才是结果。Promise
是一个状态机,初始状态为 pending
,一旦确定状态为 resolved
或 rejected
就不会改变,可以通过 .then
和 .catch
进行链式调用。async
/await
stimmt mit der browserseitigen Bedienung überein.
callback
Callback-Funktionsformatspezifikation🎜error-first callback🎜🎜<code>node-style callback
🎜🎜🎜🎜Der erste Parameter ist error
, und die folgenden Parameter sind das Ergebnis. 🎜🎜rrreee🎜Asynchrone Prozesssteuerung: Callback-Hölle, asynchrone Parallelität und andere Probleme🎜🎜🎜npm
: async.js
kann an async.js übergeben werden; code> Zur Steuerung asynchroner Prozesse🎜🎜<code>thunk
: eine Programmiermethode🎜🎜Versprechen
🎜 🎜🎜 kann wörtlich verstanden werden. Promise
bedeutet, dass die aktuelle Ereignisschleife das Ergebnis nicht erhalten kann, aber die zukünftige Ereignisschleife wird Ihnen das Ergebnis liefern. Es handelt sich einmal um eine Zustandsmaschine Der Status wird als aufgelöst
oder abgelehnt
bestimmt, er ändert sich nicht🎜🎜ausstehend
: Anfangsstatus, der Status, in dem das Ergebnis noch nicht vorhanden war noch erhalten🎜🎜erfüllt
/ gelöst
: Erfolgsstatus 🎜🎜abgelehnt
: Fehlerstatus 🎜🎜🎜🎜🎜Kettenaufruf: .then
und der .catch
🎜🎜🎜resolved
Status Promise
rufen das erste .then
🎜 zurück 🎜Promise
im Status >abgelehnt.catch
zurück. 🎜🎜Jeder abgelehnte
-Status, der dies nicht tut Wenn Sie dem Promise
von .catch
folgen, wird ein globaler Fehler in der Browser-/Knotenumgebung verursacht. 🎜🎜rrreee🎜Das Ausführen von then
und catch
will Gibt ein neues Promise
zurück, dessen endgültiger Zustand basierend auf den Ausführungsergebnissen der Rückruffunktionen von then
und catch
bestimmt wird 🎜🎜 🎜Wenn die Callback-Funktion am Ende throw
ist, befindet sich das Promise
im Status rejected
. 🎜🎜Wenn die Callback-Funktion am Ende ist return
, Das Promise
befindet sich im Status aufgelöst
🎜🎜Aber wenn die Rückruffunktion schließlich zurückgibt
ein Promise code>, das <code>Promise
stimmt mit dem Promise
-Status der Rückruffunktion return
überein 🎜🎜await
🎜🎜🎜async function
ist ein syntaktisches Zuckerpaket von Versprechen
🎜🎜für asynchrone Programmierung Die ultimative Lösung – asynchron auf synchrone Weise schreiben🎜🎜 Das Schlüsselwort await
kann die Ausführung der asynchronen Funktion
„anhalten“🎜🎜 Das Schlüsselwort await
kann verwendet werden. Die synchrone Schreibmethode erhält das Ausführungsergebnis von Promise
🎜🎜try-catch
kann den von await erhaltenen Fehler abrufen
🎜🎜🎜🎜rrreee🎜Dies ist eine A-Funktion
, die über die Ereignisschleife existiert. 🎜error
ist und das Folgende das Ergebnis ist. 🎜🎜Promise
ist eine 🎜Zustandsmaschine🎜 Der Anfangszustand ist ausstehend
. Sobald der Zustand bestimmt ist, ist er aufgelöst
abgelehnt Es ändert sich nicht und Kettenaufrufe können über .then
und .catch
durchgeführt werden. 🎜🎜async
/await
🎜Asynchrones Schreiben auf synchrone Weise🎜 ist die ultimative Lösung für die asynchrone Programmierung. 🎜🎜🎜Weitere Programmierkenntnisse finden Sie unter: 🎜Programmiervideo🎜! ! 🎜Das obige ist der detaillierte Inhalt vonEine eingehende Analyse der Asynchronität in Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!