


Detaillierte Erläuterung der async+await-Synchronisations-/asynchronen Lösung von ES6
Dieser Artikel stellt hauptsächlich die detaillierte Erklärung der asynchronen + wartenden Synchronisierungs-/Asynchronlösung von ES6 vor. In diesem Artikel wird die prägnanteste Methode zum Entsperren von asynchronem Warten und Warten verwendet. Interessierte können mehr darüber erfahren.
Asynchrone Programmierung war JavaScript-Programmierung wichtige Themen. In Bezug auf asynchrone Lösungen entstand in ES6 zunächst Promise basierend auf der Zustandsverwaltung, dann die Generatorfunktion + Co-Funktion und dann die asynchrone + Wait-Lösung von ES7.
Dieser Artikel ist bestrebt, Async + Wait auf prägnanteste Weise zu entsperren.
Mehrere Szenarien der asynchronen Programmierung
Beginnen Sie mit einer häufig gestellten Frage: Wie druckt man die Iterationssequenz asynchron in einer for-Schleife?
Wir können uns leicht vorstellen, Schließungen oder den in ES6 angegebenen Let-Block-Level-Bereich zu verwenden, um diese Frage zu beantworten.
for (let val of [1, 2, 3, 4]) { setTimeout(() => console.log(val),100); } // => 预期结果依次为:1, 2, 3, 4
Was hier beschrieben wird, ist eine Synchronisierung, die gleichmäßig erfolgt und in einer vorgegebenen Reihenfolge in der asynchronen Warteschlange eingereiht wird, um auf die Ausführung zu warten.
Wenn die Asynchronität nicht gleichmäßig erfolgt, ist die Reihenfolge, in der sie in der asynchronen Warteschlange registriert werden, nicht in der richtigen Reihenfolge.
for (let val of [1, 2, 3, 4]) { setTimeout(() => console.log(val), 100 * Math.random()); } // => 实际结果是随机的,依次为:4, 2, 3, 1
Die zurückgegebenen Ergebnisse sind außer Betrieb und unkontrollierbar, was asynchron am realistischsten ist. Eine andere Situation ist jedoch, dass Sie in einer Schleife Folgendes tun sollten, wenn Sie möchten, dass die vorherige asynchrone Ausführung abgeschlossen wird und die nächste asynchrone Ausführung erneut ausgeführt wird.
for (let val of ['a', 'b', 'c', 'd']) { // a 执行完后,进入下一个循环 // 执行 b,依此类推 }
Sind das nicht einfach mehrere asynchrone „Serien“?
Die Methode, asynchrone Vorgänge im Rückruf zu verschachteln und dann zurückzurufen, löst dieses Problem! Alternativ kann das Problem auch durch die Verwendung von Promise + then() zum Verschachteln von Ebenen gelöst werden. Wenn Sie jedoch darauf bestehen, diese Verschachtelungsmethode in einer Schleife zu schreiben, befürchte ich, dass dies große Probleme verursachen wird. Ich frage mich, gibt es einen besseren Weg?
Asynchrone Synchronisationslösung
Stellen Sie sich vor, wenn Sie einen Datenstapel an den Server senden möchten, wird nur der vorherige Stapel erfolgreich gesendet (d. h. der Server gibt a zurück). erfolgreiche Antwort), Erst dann wird der nächste Datenstapel gesendet, andernfalls wird der Versand abgebrochen. Dies ist ein typisches Beispiel für „interdependente asynchrone Operationen in einer for-Schleife“.
Offensichtlich kann dieser „serielle“ Asynchronismus tatsächlich als Synchronisation angesehen werden. Es dauert länger als asynchrones Out-of-Order. Logischerweise möchten wir, dass das Programm asynchron ausgeführt wird, nur um Blockierungen zu „überspringen“ und weniger Zeit zu benötigen. Aber im Gegenteil, wenn wir eine Reihe asynchroner „Serien“ benötigen, wie sollten wir dann gut programmieren?
Für diese „serielle“ Asynchronität kann ES6 dieses Problem leicht lösen.
async function task () { for (let val of [1, 2, 3, 4]) { // await 是要等待响应的 let result = await send(val); if (!result) { break; } } } task();
Im wahrsten Sinne des Wortes ist es dieser Zyklus. Sobald die Ergebnisse vorliegen, wird der nächste Zyklus durchgeführt. Daher wird die Schleife bei jeder Ausführung angehalten („hängengeblieben“), bis die Schleife endet. Diese Codierungsimplementierung beseitigt effektiv das Problem der verschachtelten „Callback-Hölle“ und reduziert kognitive Schwierigkeiten.
Dies ist die Lösung zur Synchronisierung asynchroner Probleme. Wenn Promise in Bezug auf diese Lösung hauptsächlich das Problem asynchroner Rückrufe löst, löst Async + Wait hauptsächlich das Problem der Synchronisierung asynchroner Probleme und verringert die kognitive Belastung durch asynchrone Programmierung.
async + waiting „äußerlich unterschiedlich, aber innen gleich“
Als ich früher mit dieser API in Kontakt kam, habe ich mir die umständliche Dokumentation angeschaut und Ich dachte, dass Async + Await hauptsächlich zur Lösung des Problems verwendet wurde. Asynchrone Probleme sind synchron.
Das ist nicht der Fall. Wie aus dem obigen Beispiel ersichtlich ist: Das Schlüsselwort async deklariert eine asynchrone Funktion. Der Hauptteil dieser asynchronen Funktion enthält eine Zeile mit Warteanweisungen, die benachrichtigen, dass das Verhalten synchron ausgeführt wird, und die angrenzenden Codes oben und unten werden ausgeführt Zeile für Zeile der Reihe nach.
Um diese formale Sache noch einmal zu übersetzen:
1 Nachdem die asynchrone Funktion ausgeführt wurde, wird immer ein Promise-Objekt zurückgegeben
2 ist synchron
Darunter zeigt 1, dass die Task-Methode nach der Ausführung ein Promise-Objekt zurückgibt. Da sie ein Promise zurückgibt, kann man verstehen, dass die Task eine asynchrone Methode ist. Es besteht kein Zweifel, dass es so verwendet wird:
task().then((val) => {alert(val)}) .then((val) => {alert(val)})
2 zeigt, dass innerhalb der Task-Funktion Asynchronität in Synchronisation „geschnitten“ wurde. Das Ganze ist nur eine Funktion, deren Ausführung etwas Zeit in Anspruch nimmt.
Aus formaler Sicht ist die Synthese von 1 und 2 „die Aufgabe als Ganzes eine asynchrone Funktion und der gesamte interne Teil ist synchron“, was als „äußerlich unterschiedlich, aber unterschiedlich“ bezeichnet wird das Gleiche auch im Inneren".
Die gesamte Funktion ist eine asynchrone Funktion, die nicht schwer zu verstehen ist. In Bezug auf die Implementierung können wir es genauso gut umkehren. Wenn das Schlüsselwort async aufgerufen wird, muss am Ende der Funktionsausführung ein Versprechen hinzugefügt werden:
async fn () { let result; // ... //末尾返回 promise return isPromise(result)? result : Promise.resolve(undefined); }
ist intern Wie wird die Synchronisation erreicht? Tatsächlich führt der Warteaufruf dazu, dass die folgenden Anweisungen (Funktionen) rekursiv ausgeführt werden. Sie werden erst dann aufgelöst, wenn das Ergebnis vorliegt und ihr Status geändert wird. Erst nachdem die Auflösung aufgelöst wurde, gilt die Wartecodezeile als abgeschlossen und wird mit der Ausführung zur nächsten Zeile fortfahren. Obwohl es außerhalb eine große for-Schleife gibt, wird daher die gesamte for-Schleife der Reihe nach serialisiert.
Allein aus dem Erscheinungsbild des obigen Frameworks ist es also nicht schwer, die Bedeutung von Async + Wait zu verstehen. Es ist einfach zu bedienen, aber Promise ist ein grundlegendes Stück, das man beherrschen muss.
秉承本次《重读 ES6》系列的原则,不过多追求理解细节和具体实现过程。我们继续巩固一下这个 “形式化” 的理解。
async + await 的进一步理解
有这样的一个异步操作 longTimeTask,已经用 Promise 进行了包装。借助该函数进行一系列验证。
const longTimeTask = function (time) { return new Promise((resolve, reject) => { setTimeout(()=>{ console.log(`等了 ${time||'xx'} 年,终于回信了`); resolve({'msg': 'task done'}); }, time||1000) }) }
async 函数的执行情况
如果,想查看 async exec1 函数的返回结果,以及 await 命令的执行结果:
const exec1 = async function () { let result = await longTimeTask(); console.log('result after long time ===>', result); } // 查看函数内部执行顺序 exec1(); // => 等了 xx 年,终于回信了 // => result after long time ===> Object {msg: "task done"} //查看函数总体返回值 console.log(exec1()); // => Promise {[[PromiseStatus]]: "pending",...} // => 同上
以上 2 步执行,清晰的证明了 exec1 函数体内是同步、逐行逐行执行的,即先执行完异步操作,然后进行 console.log() 打印。而 exec1() 的执行结果就直接是一个 Promise,因为它最先会蹦出来一串 Promise ...,然后才是 exec1 函数的内部执行日志。
因此,所有验证,完全符合 整体是一个异步函数,内部整个是同步的 的总结。
await 如何执行其后语句?
回到 await ,看看它是如何执行其后边的语句的。假设:让 longTimeTask() 后边直接带 then() 回调,分两种情况:
1)then() 中不再返回任何东西
2) then() 中继续手动返回另一个 promise
const exec2 = async function () { let result = await longTimeTask().then((res) => { console.log('then ===>', res.msg); res.msg = `${res.msg} then refrash message`; // 注释掉这条 return 或 手动返回一个 promise return Promise.resolve(res); }); console.log('result after await ===>', result.msg); } exec2(); // => 情况一 TypeError: Cannot read property 'msg' of undefined // => 情况二 正常
首先,longTimeTask() 加上再多得 then() 回调,也不过是放在了它的回调列队 queue 里了。也就是说,await 命令之后始终是一条 表达式语句,只不过上述代码书写方式比较让人迷惑。(比较好的实践建议是,将 longTimeTask 方法身后的 then() 移入 longTimeTask 函数体封装起来)
其次,手动返回另一个 promise 和什么也不返回,关系到 longTimeTask() 方法最终 resolve 出去的内容不一样。换句话说,await 命令会提取其后边的promise 的 resolve 结果,进而直接导致 result 的不同。
值得强调的是,await 命令只认 resolve 结果,对 reject 结果报错。不妨用以下的 return 语句替换上述 return 进行验证。
return Promise.reject(res);
最后
其实,关于异步编程还有很多可以梳理的,比如跨模块的异步编程、异步的单元测试、异步的错误处理以及什么是好的实践。All in all, 限于篇幅,不在此汇总了。最后,async + await 确实是一个很优雅的方案。
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der async+await-Synchronisations-/asynchronen Lösung von ES6. 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



Detaillierte Erläuterung der Modusfunktion in C++ In der Statistik bezieht sich der Modus auf den Wert, der in einem Datensatz am häufigsten vorkommt. In der Sprache C++ können wir den Modus in jedem Datensatz finden, indem wir eine Modusfunktion schreiben. Die Modusfunktion kann auf viele verschiedene Arten implementiert werden. Zwei der häufig verwendeten Methoden werden im Folgenden ausführlich vorgestellt. Die erste Methode besteht darin, eine Hash-Tabelle zu verwenden, um die Häufigkeit des Vorkommens jeder Zahl zu zählen. Zuerst müssen wir eine Hash-Tabelle definieren, in der jede Zahl der Schlüssel und die Häufigkeit des Vorkommens der Wert ist. Dann führen wir für einen bestimmten Datensatz aus

Das Windows-Betriebssystem ist eines der beliebtesten Betriebssysteme der Welt und seine neue Version Win11 hat viel Aufmerksamkeit erregt. Im Win11-System ist die Erlangung von Administratorrechten ein wichtiger Vorgang. Mit Administratorrechten können Benutzer weitere Vorgänge und Einstellungen auf dem System durchführen. In diesem Artikel wird ausführlich beschrieben, wie Sie Administratorrechte im Win11-System erhalten und wie Sie Berechtigungen effektiv verwalten. Im Win11-System werden Administratorrechte in zwei Typen unterteilt: lokaler Administrator und Domänenadministrator. Ein lokaler Administrator verfügt über vollständige Administratorrechte für den lokalen Computer

Detaillierte Erläuterung der Divisionsoperation in OracleSQL In OracleSQL ist die Divisionsoperation eine häufige und wichtige mathematische Operation, die zur Berechnung des Ergebnisses der Division zweier Zahlen verwendet wird. Division wird häufig in Datenbankabfragen verwendet. Daher ist das Verständnis der Divisionsoperation und ihrer Verwendung in OracleSQL eine der wesentlichen Fähigkeiten für Datenbankentwickler. In diesem Artikel werden die relevanten Kenntnisse über Divisionsoperationen in OracleSQL ausführlich erörtert und spezifische Codebeispiele als Referenz für die Leser bereitgestellt. 1. Divisionsoperation in OracleSQL

Detaillierte Erläuterung der Restfunktion in C++ In C++ wird der Restoperator (%) verwendet, um den Rest der Division zweier Zahlen zu berechnen. Es handelt sich um einen binären Operator, dessen Operanden ein beliebiger Ganzzahltyp (einschließlich char, short, int, long usw.) oder ein Gleitkommazahlentyp (z. B. float, double) sein kann. Der Restoperator gibt ein Ergebnis mit demselben Vorzeichen wie der Dividend zurück. Für die Restoperation von Ganzzahlen können wir beispielsweise den folgenden Code zur Implementierung verwenden: inta=10;intb=3;

Detaillierte Erläuterung der Verwendung der Vue.nextTick-Funktion und ihrer Anwendung bei asynchronen Aktualisierungen. Bei der Vue-Entwicklung treten häufig Situationen auf, in denen Daten asynchron aktualisiert werden müssen. Beispielsweise müssen Daten sofort nach einer Änderung des DOM oder verwandter Vorgänge aktualisiert werden unmittelbar nach der Aktualisierung der Daten durchzuführen. Die von Vue bereitgestellte Funktion .nextTick wurde entwickelt, um diese Art von Problem zu lösen. In diesem Artikel wird die Verwendung der Vue.nextTick-Funktion im Detail vorgestellt und mit Codebeispielen kombiniert, um ihre Anwendung bei asynchronen Updates zu veranschaulichen. 1. Vue.nex

PHP-FPM ist ein häufig verwendeter PHP-Prozessmanager, der eine bessere PHP-Leistung und -Stabilität bietet. In einer Hochlastumgebung erfüllt die Standardkonfiguration von PHP-FPM jedoch möglicherweise nicht die Anforderungen, sodass wir sie optimieren müssen. In diesem Artikel wird die Optimierungsmethode von PHP-FPM ausführlich vorgestellt und einige Codebeispiele gegeben. 1. Erhöhen Sie die Anzahl der Prozesse. Standardmäßig startet PHP-FPM nur eine kleine Anzahl von Prozessen, um Anfragen zu bearbeiten. In einer Hochlastumgebung können wir die Parallelität von PHP-FPM erhöhen, indem wir die Anzahl der Prozesse erhöhen.

Der Modulo-Operator (%) in PHP wird verwendet, um den Rest der Division zweier Zahlen zu ermitteln. In diesem Artikel werden wir die Rolle und Verwendung des Modulo-Operators im Detail besprechen und spezifische Codebeispiele bereitstellen, um den Lesern ein besseres Verständnis zu erleichtern. 1. Die Rolle des Modulo-Operators Wenn wir in der Mathematik eine ganze Zahl durch eine andere ganze Zahl dividieren, erhalten wir einen Quotienten und einen Rest. Wenn wir beispielsweise 10 durch 3 dividieren, ist der Quotient 3 und der Rest ist 1. Um diesen Rest zu ermitteln, wird der Modulo-Operator verwendet. 2. Verwendung des Modulo-Operators In PHP verwenden Sie das %-Symbol, um den Modul darzustellen

Detaillierte Erläuterung der Funktion system() des Linux-Systems Der Systemaufruf ist ein sehr wichtiger Teil des Linux-Betriebssystems. Er bietet eine Möglichkeit, mit dem Systemkernel zu interagieren. Unter diesen ist die Funktion system() eine der am häufigsten verwendeten Systemaufruffunktionen. In diesem Artikel wird die Verwendung der Funktion system() ausführlich vorgestellt und entsprechende Codebeispiele bereitgestellt. Grundlegende Konzepte von Systemaufrufen Systemaufrufe sind eine Möglichkeit für Benutzerprogramme, mit dem Betriebssystemkernel zu interagieren. Benutzerprogramme fordern das Betriebssystem an, indem sie Systemaufruffunktionen aufrufen
