🔜
Vorausgesetzte Kenntnisse
Bevor wir mit dem Haupttext beginnen, wollen wir im Voraus den Ton für einige Inhalte dieses Artikels festlegen.Versprechen Welche APIs beinhalten Mikrotasks?
In Promise gelten nur Rückrufe, die nach Zustandsänderungen ausgeführt werden müssen, als Mikrotasks, wie z. B.then
,catch
undfinally
. Alle anderen Codeausführungen sind Makroaufgaben (synchrone Ausführung).

Im Bild oben steht Blau für die synchrone Ausführung und Gelb für die asynchrone Ausführung (in die Mikrotask-Warteschlange geworfen).
Wann werden diese Mikrotasks zur Mikrotask-Warteschlange hinzugefügt? Sehen wir uns dieses Problem gemäß der Ecma-Spezifikation an:
- Wenn der Promise-Status zu diesem Zeitpunkt aussteht, werden die erfolgreichen oder fehlgeschlagenen Rückrufe zu
[[PromiseFulfillReactions]] und <code>[[PromiseRejectReactions]]
. Wenn Sie sich den handgeschriebenen Promise-Code angesehen haben, sollten Sie feststellen, dass es zwei Arrays gibt, in denen diese Rückruffunktionen gespeichert sind. - Wenn der Promise-Status zu diesem Zeitpunkt nicht ausstehend ist, wird der Rückruf zu Promise-Jobs, bei denen es sich um Mikrotasks handelt.
then
、 catch
、finally
,其他所有的代码执行都是宏任务(同步执行)。
上图中蓝色为同步执行,黄色为异步执行(丢到微任务队列中)。
这些微任务何时被加入微任务队列?
这个问题我们根据 ecma 规范来看:
如果此时 Promise 状态为 pending,那么成功或失败的回调会分别被加入至
[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
中。如果你看过手写 Promise 的代码的话,应该能发现有两个数组存储这些回调函数。如果此时 Promise 状态为非 pending 时,回调会成为 Promise Jobs,也就是微任务。
了解完以上知识后,正片开始。
同一个 then,不同的微任务执行
初级
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }) .then(() => { console.log("then2"); });复制代码
以上代码大家应该都能得出正确的答案:then1 → then1-1 → then2
。
虽然 then
是同步执行,并且状态也已经变更。但这并不代表每次遇到 then
时我们都需要把它的回调丢入微任务队列中,而是等待 then
的回调执行完毕后再根据情况执行对应操作。
基于此,我们可以得出第一个结论:链式调用中,只有前一个 then
的回调执行完毕后,跟着的 then
中的回调才会被加入至微任务队列。
中级
大家都知道了 Promise resolve
后,跟着的 then
中的回调会马上进入微任务队列。
那么以下代码你认为的输出会是什么?
let p = Promise.resolve(); p.then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then1-2"); }); p.then(() => { console.log("then2"); }); 复制代码
按照一开始的认知我们不难得出 then2
会在 then1-1
后输出,但是实际情况却是相反的。
基于此我们得出第二个结论:每个链式调用的开端会首先依次进入微任务队列。
接下来我们换个写法:
let p = Promise.resolve().then(() => { console.log("then1"); Promise.resolve().then(() => { console.log("then1-1"); }); }).then(() => { console.log("then2"); }); p.then(() => { console.log("then3"); });复制代码
上述代码其实有个陷阱,then
每次都会返回一个新的 Promise,此时的 p
已经不是 Promise.resolve()
生成的,而是最后一个 then
生成的,因此 then3
应该是在 then2
后打印出来的。
顺便我们也可以把之前得出的结论优化为:同一个 Promise 的每个链式调用的开端会首先依次进入微任务队列。
高级
以下大家可以猜猜 then1-2
会在何时打印出来?
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return 1; }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });复制代码
这题肯定是简单的,记住第一个结论就能得出答案,以下是解析:
第一次
resolve
后第一个then
的回调进入微任务队列并执行,打印then1
第二次
resolve
后内部第一个then
的回调进入微任务队列,此时外部第一个then
的回调全部执行完毕,需要将外部的第二个then
回调也插入微任务队列。执行微任务,打印
then1-1
和then2
,然后分别再将之后then
中的回调插入微任务队列执行微任务,打印
then1-2
和then3
,之后的内容就不一一说明了
接下来我们把 return 1
修改一下,结果可就大不相同啦:
Promise.resolve() .then(() => { console.log("then1"); Promise.resolve() .then(() => { console.log("then1-1"); return Promise.resolve(); }) .then(() => { console.log("then1-2"); }); }) .then(() => { console.log("then2"); }) .then(() => { console.log("then3"); }) .then(() => { console.log("then4"); });复制代码
当我们 return Promise.resolve()
时,你猜猜 then1-2
会何时打印了?
答案是最后一个才被打印出来。
为什么在 then
中分别 return
Nachdem wir die oben genannten Kenntnisse verstanden haben, beginnt der Hauptfilm.
Dann das Gleiche, unterschiedliche Ausführung von Mikroaufgaben🎜Elementar🎜if (x instanceof MyPromise) { if (x.currentState === PENDING) {
} else {
x.then(resolve, reject);
} return;
}复制代码
🎜Jeder sollte in der Lage sein, das zu bekommen obiger Code Geben Sie die richtige Antwort ein: then1 → then1-1 → then2
. 🎜🎜Obwohl then
synchron ausgeführt wird und sich der Status geändert hat. Dies bedeutet jedoch nicht, dass wir jedes Mal, wenn wir auf then
stoßen, dessen Rückruf in die Mikrotask-Warteschlange werfen müssen. Stattdessen müssen wir warten, bis der Rückruf von then
abgeschlossen ist und verwenden Sie es dann entsprechend der Situation. 🎜🎜Auf dieser Grundlage können wir die erste Schlussfolgerung ziehen: Bei Kettenaufrufen wird erst nach dem vorherigen dann
Rückruf ausgeführt, der folgende Nur Der Rückruf in strong>then
wird zur Mikrotask-Warteschlange hinzugefügt. 🎜Mittelstufe 🎜🎜Jeder weiß, dass nach Versprechen gelöst
der Rückruf im folgenden dann
sofort eingegeben wird die Mikrotask-Warteschlange. 🎜🎜Was wird Ihrer Meinung nach die Ausgabe des folgenden Codes sein? 🎜rrreee🎜Nach unserem anfänglichen Verständnis ist es nicht schwer zu schließen, dass then2
nach then1-1
ausgegeben wird, aber die tatsächliche Situation ist das Gegenteil. 🎜🎜Auf dieser Grundlage ziehen wir die zweite Schlussfolgerung:Der Beginn jedes Kettenaufrufs gelangt zuerst nacheinander in die Mikrotask-Warteschlange. 🎜🎜Als nächstes ändern wir die Schreibweise: 🎜rrreee🎜Der obige Code hat tatsächlich eine Falle, then
gibt zu diesem Zeitpunkt ein neues Versprechen zurück Es wird nicht mehr von Promise.resolve()
generiert, sondern vom letzten then
, daher sollte then3
in then2 code> wird ausgedruckt. 🎜🎜Übrigens können wir auch die Schlussfolgerung, zu der wir zuvor gelangt sind, optimieren:Der Anfang jedes Kettenaufrufs desselben Versprechens wird zuerst nacheinander in die Mikrotask-Warteschlange eingegeben. 🎜Erweitert🎜🎜 Können Sie erraten, wann then1-2
gedruckt wird? 🎜rrreee🎜Diese Frage ist definitiv einfach. Merken Sie sich einfach die erste Schlussfolgerung und Sie können die Antwort erhalten: 🎜
- 🎜Der erste
resolve
Rückruf von Code >then tritt in die Mikrotask-Warteschlange ein und wird ausgeführt, wobei der erste interne nach then1
🎜
- 🎜 beim zweiten Mal
resolve
gedruckt wird Der Rückruf von then
gelangt in die Mikrotask-Warteschlange. Zu diesem Zeitpunkt wurden alle Rückrufe des ersten externen then
und des zweiten externen then
ausgeführt > muss ausgeführt werden. Rückrufe werden ebenfalls in die Mikrotask-Warteschlange eingefügt. 🎜
- 🎜Führen Sie die Mikroaufgabe aus, geben Sie
then1-1
und then2
aus und rufen Sie dann die Rückrufe in then
bzw. Einfügen auf die Mikrotask-Warteschlange🎜
- 🎜Führen Sie die Mikrotask aus, drucken Sie
then1-2
und then3
, der folgende Inhalt wird nicht einzeln erklärt🎜 li>
🎜Als nächstes modifizieren wir return 1
, und das Ergebnis ist ganz anders: 🎜rrreee🎜Wenn wir return Promise.resolve()
, rate wann then1-2
wird gedruckt? 🎜🎜Die Antwort ist die zuletzt gedruckte. 🎜🎜Warum gibt es eine so große Änderung in der Ausführungsreihenfolge von Mikrotasks, wenn es return
verschiedene Dinge in then
gibt? Das Folgende ist die Analyse des Autors. 🎜
if (x instanceof MyPromise) { if (x.currentState === PENDING) { } else { x.then(resolve, reject); } return; }复制代码🎜Jeder sollte in der Lage sein, das zu bekommen obiger Code Geben Sie die richtige Antwort ein:
then1 → then1-1 → then2
. 🎜🎜Obwohl then
synchron ausgeführt wird und sich der Status geändert hat. Dies bedeutet jedoch nicht, dass wir jedes Mal, wenn wir auf then
stoßen, dessen Rückruf in die Mikrotask-Warteschlange werfen müssen. Stattdessen müssen wir warten, bis der Rückruf von then
abgeschlossen ist und verwenden Sie es dann entsprechend der Situation. 🎜🎜Auf dieser Grundlage können wir die erste Schlussfolgerung ziehen: Bei Kettenaufrufen wird erst nach dem vorherigen dann
Rückruf ausgeführt, der folgende Nur Der Rückruf in strong>then
wird zur Mikrotask-Warteschlange hinzugefügt. 🎜Mittelstufe 🎜🎜Jeder weiß, dass nach Versprechen gelöst
der Rückruf im folgenden dann
sofort eingegeben wird die Mikrotask-Warteschlange. 🎜🎜Was wird Ihrer Meinung nach die Ausgabe des folgenden Codes sein? 🎜rrreee🎜Nach unserem anfänglichen Verständnis ist es nicht schwer zu schließen, dass then2
nach then1-1
ausgegeben wird, aber die tatsächliche Situation ist das Gegenteil. 🎜🎜Auf dieser Grundlage ziehen wir die zweite Schlussfolgerung:Der Beginn jedes Kettenaufrufs gelangt zuerst nacheinander in die Mikrotask-Warteschlange. 🎜🎜Als nächstes ändern wir die Schreibweise: 🎜rrreee🎜Der obige Code hat tatsächlich eine Falle, then
gibt zu diesem Zeitpunkt ein neues Versprechen zurück Es wird nicht mehr von Promise.resolve()
generiert, sondern vom letzten then
, daher sollte then3
in then2 code> wird ausgedruckt. 🎜🎜Übrigens können wir auch die Schlussfolgerung, zu der wir zuvor gelangt sind, optimieren:Der Anfang jedes Kettenaufrufs desselben Versprechens wird zuerst nacheinander in die Mikrotask-Warteschlange eingegeben. 🎜Erweitert🎜🎜 Können Sie erraten, wann then1-2
gedruckt wird? 🎜rrreee🎜Diese Frage ist definitiv einfach. Merken Sie sich einfach die erste Schlussfolgerung und Sie können die Antwort erhalten: 🎜
- 🎜Der erste
resolve
Rückruf von Code >then tritt in die Mikrotask-Warteschlange ein und wird ausgeführt, wobei der erste interne nach then1
🎜
- 🎜 beim zweiten Mal
resolve
gedruckt wird Der Rückruf von then
gelangt in die Mikrotask-Warteschlange. Zu diesem Zeitpunkt wurden alle Rückrufe des ersten externen then
und des zweiten externen then
ausgeführt > muss ausgeführt werden. Rückrufe werden ebenfalls in die Mikrotask-Warteschlange eingefügt. 🎜
- 🎜Führen Sie die Mikroaufgabe aus, geben Sie
then1-1
und then2
aus und rufen Sie dann die Rückrufe in then
bzw. Einfügen auf die Mikrotask-Warteschlange🎜
- 🎜Führen Sie die Mikrotask aus, drucken Sie
then1-2
und then3
, der folgende Inhalt wird nicht einzeln erklärt🎜 li>
🎜Als nächstes modifizieren wir return 1
, und das Ergebnis ist ganz anders: 🎜rrreee🎜Wenn wir return Promise.resolve()
, rate wann then1-2
wird gedruckt? 🎜🎜Die Antwort ist die zuletzt gedruckte. 🎜🎜Warum gibt es eine so große Änderung in der Ausführungsreihenfolge von Mikrotasks, wenn es return
verschiedene Dinge in then
gibt? Das Folgende ist die Analyse des Autors. 🎜
then1-2
gedruckt wird? 🎜rrreee🎜Diese Frage ist definitiv einfach. Merken Sie sich einfach die erste Schlussfolgerung und Sie können die Antwort erhalten: 🎜- 🎜Der erste
resolve
Rückruf von Code >then tritt in die Mikrotask-Warteschlange ein und wird ausgeführt, wobei der erste interne nachthen1
🎜 - 🎜 beim zweiten Mal
resolve
gedruckt wird Der Rückruf vonthen
gelangt in die Mikrotask-Warteschlange. Zu diesem Zeitpunkt wurden alle Rückrufe des ersten externenthen
und des zweiten externenthen
ausgeführt > muss ausgeführt werden. Rückrufe werden ebenfalls in die Mikrotask-Warteschlange eingefügt. 🎜 - 🎜Führen Sie die Mikroaufgabe aus, geben Sie
then1-1
undthen2
aus und rufen Sie dann die Rückrufe inthen
bzw. Einfügen auf die Mikrotask-Warteschlange🎜 - 🎜Führen Sie die Mikrotask aus, drucken Sie
then1-2
undthen3
, der folgende Inhalt wird nicht einzeln erklärt🎜 li>
return 1
, und das Ergebnis ist ganz anders: 🎜rrreee🎜Wenn wir return Promise.resolve()
, rate wann then1-2
wird gedruckt? 🎜🎜Die Antwort ist die zuletzt gedruckte. 🎜🎜Warum gibt es eine so große Änderung in der Ausführungsreihenfolge von Mikrotasks, wenn es return
verschiedene Dinge in then
gibt? Das Folgende ist die Analyse des Autors. 🎜PS:then
返回一个新的 Promise,并且会用这个 Promise 去 resolve
返回值,这个概念需要大家先了解一下。
根据 Promise A+ 规范
根据规范 2.3.2,如果 resolve
了一个 Promise,需要为其加上一个 then
并 resolve
。
if (x instanceof MyPromise) { if (x.currentState === PENDING) { } else { x.then(resolve, reject); } return; }复制代码
上述代码节选自手写 Promise 实现。
那么根据 A+ 规范来说,如果我们在 then
中返回了 Promise.resolve
的话会多入队一次微任务,但是这个结论还是与实际不符的,因此我们还需要寻找其他权威的文档。
根据 ECMA - 262 规范
根据规范 25.6.1.3.2,当 Promise resolve
了一个 Promise 时,会产生一个NewPromiseResolveThenableJob,这是属于 Promise Jobs 中的一种,也就是微任务。
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
并且该 Jobs 还会调用一次 then
函数来 resolve Promise
,这也就又生成了一次微任务。
这就是为什么会触发两次微任务的来源。
最后
文章到这里就完结了,大家有什么疑问都可以在评论区提出。
想了解更多编程学习,敬请关注php培训栏目!
Das obige ist der detaillierte Inhalt vonVersprechen, die wirklich verstanden werden müssen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Es ist für Entwickler wichtig, zu verstehen, wie die JavaScript -Engine intern funktioniert, da sie effizientere Code schreibt und Leistungs Engpässe und Optimierungsstrategien verstehen kann. 1) Der Workflow der Engine umfasst drei Phasen: Parsen, Kompilieren und Ausführung; 2) Während des Ausführungsprozesses führt die Engine dynamische Optimierung durch, wie z. B. Inline -Cache und versteckte Klassen. 3) Zu Best Practices gehören die Vermeidung globaler Variablen, die Optimierung von Schleifen, die Verwendung von const und lass und die Vermeidung übermäßiger Verwendung von Schließungen.

Python eignet sich besser für Anfänger mit einer reibungslosen Lernkurve und einer kurzen Syntax. JavaScript ist für die Front-End-Entwicklung mit einer steilen Lernkurve und einer flexiblen Syntax geeignet. 1. Python-Syntax ist intuitiv und für die Entwicklung von Datenwissenschaften und Back-End-Entwicklung geeignet. 2. JavaScript ist flexibel und in Front-End- und serverseitiger Programmierung weit verbreitet.

Python und JavaScript haben ihre eigenen Vor- und Nachteile in Bezug auf Gemeinschaft, Bibliotheken und Ressourcen. 1) Die Python-Community ist freundlich und für Anfänger geeignet, aber die Front-End-Entwicklungsressourcen sind nicht so reich wie JavaScript. 2) Python ist leistungsstark in Bibliotheken für Datenwissenschaft und maschinelles Lernen, während JavaScript in Bibliotheken und Front-End-Entwicklungsbibliotheken und Frameworks besser ist. 3) Beide haben reichhaltige Lernressourcen, aber Python eignet sich zum Beginn der offiziellen Dokumente, während JavaScript mit Mdnwebdocs besser ist. Die Wahl sollte auf Projektbedürfnissen und persönlichen Interessen beruhen.

Die Verschiebung von C/C zu JavaScript erfordert die Anpassung an dynamische Typisierung, Müllsammlung und asynchrone Programmierung. 1) C/C ist eine statisch typisierte Sprache, die eine manuelle Speicherverwaltung erfordert, während JavaScript dynamisch eingegeben und die Müllsammlung automatisch verarbeitet wird. 2) C/C muss in den Maschinencode kompiliert werden, während JavaScript eine interpretierte Sprache ist. 3) JavaScript führt Konzepte wie Verschlüsse, Prototypketten und Versprechen ein, die die Flexibilität und asynchrone Programmierfunktionen verbessern.

Unterschiedliche JavaScript -Motoren haben unterschiedliche Auswirkungen beim Analysieren und Ausführen von JavaScript -Code, da sich die Implementierungsprinzipien und Optimierungsstrategien jeder Engine unterscheiden. 1. Lexikalanalyse: Quellcode in die lexikalische Einheit umwandeln. 2. Grammatikanalyse: Erzeugen Sie einen abstrakten Syntaxbaum. 3. Optimierung und Kompilierung: Generieren Sie den Maschinencode über den JIT -Compiler. 4. Führen Sie aus: Führen Sie den Maschinencode aus. V8 Engine optimiert durch sofortige Kompilierung und versteckte Klasse.

Zu den Anwendungen von JavaScript in der realen Welt gehören die serverseitige Programmierung, die Entwicklung mobiler Anwendungen und das Internet der Dinge. Die serverseitige Programmierung wird über node.js realisiert, die für die hohe gleichzeitige Anfrageverarbeitung geeignet sind. 2. Die Entwicklung der mobilen Anwendungen erfolgt durch reaktnative und unterstützt die plattformübergreifende Bereitstellung. 3.. Wird für die Steuerung von IoT-Geräten über die Johnny-Five-Bibliothek verwendet, geeignet für Hardware-Interaktion.

Ich habe eine funktionale SaaS-Anwendung mit mehreren Mandanten (eine EdTech-App) mit Ihrem täglichen Tech-Tool erstellt und Sie können dasselbe tun. Was ist eine SaaS-Anwendung mit mehreren Mietern? Mit Multi-Tenant-SaaS-Anwendungen können Sie mehrere Kunden aus einem Sing bedienen

Dieser Artikel zeigt die Frontend -Integration mit einem Backend, das durch die Genehmigung gesichert ist und eine funktionale edtech SaaS -Anwendung unter Verwendung von Next.js. erstellt. Die Frontend erfasst Benutzerberechtigungen zur Steuerung der UI-Sichtbarkeit und stellt sicher, dass API-Anfragen die Rollenbasis einhalten


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

Herunterladen der Mac-Version des Atom-Editors
Der beliebteste Open-Source-Editor

SAP NetWeaver Server-Adapter für Eclipse
Integrieren Sie Eclipse mit dem SAP NetWeaver-Anwendungsserver.

SecLists
SecLists ist der ultimative Begleiter für Sicherheitstester. Dabei handelt es sich um eine Sammlung verschiedener Arten von Listen, die häufig bei Sicherheitsbewertungen verwendet werden, an einem Ort. SecLists trägt dazu bei, Sicherheitstests effizienter und produktiver zu gestalten, indem es bequem alle Listen bereitstellt, die ein Sicherheitstester benötigen könnte. Zu den Listentypen gehören Benutzernamen, Passwörter, URLs, Fuzzing-Payloads, Muster für vertrauliche Daten, Web-Shells und mehr. Der Tester kann dieses Repository einfach auf einen neuen Testcomputer übertragen und hat dann Zugriff auf alle Arten von Listen, die er benötigt.

VSCode Windows 64-Bit-Download
Ein kostenloser und leistungsstarker IDE-Editor von Microsoft