Derzeit ist eine große Anzahl von asynchronen Operationen an der Nachfrage beteiligt, und die tatsächlichen Seiten sind zunehmend zu einseitigen Anwendungen geneigt. In Zukunft können Sie Rückgrat, Angular, Knockout und andere Frameworks verwenden, aber das Problem der asynchronen Programmierung ist das erste Problem, mit dem sie konfrontiert sind. Mit dem Aufstieg der Knoten ist die asynchrone Programmierung zu einem sehr heißen Thema geworden. Nach einer Zeit des Lernens und der Praxis werden einige Details der asynchronen Programmierung zusammengefasst.
1. Klassifizierung der asynchronen Programmierung
Zu den Methoden zur Lösung des asynchronen Problems gehören im Allgemeinen: Direkter Rückruf, Pub/Sub -Modus (Ereignismodus), Asynchronous Library Control Library (z. B. Async, wenn), Versprechen, Generator usw.
1.1 Rückruffunktion
Rückruffunktionen werden üblicherweise verwendet, um asynchrone Lösungen zu lösen, die häufig exponiert und verwendet, leicht zu verstehen und in Bibliotheken oder Funktionen sehr einfach zu implementieren sind. Dies ist auch eine Methode, die Menschen häufig verwenden, wenn sie eine asynchrone Programmierung verwenden.
Die Rückruffunktionsmethode hat jedoch die folgenden Probleme:
1. Eine verschachtelte Pyramide des Bösen kann gebildet werden, und der Code ist nicht leicht zu lesen;
2. Es kann nur eine Rückruffunktion entsprechen, was in vielen Szenarien zu einer Grenze wird.
1.2 Pub/Sub -Modus (Ereignis)
Dieses Muster wird auch als Ereignismodus bezeichnet, nämlich die Ereignis von Rückruffunktionen und ist in Klassenbibliotheken wie JQuery sehr häufig.
Das Ereignisveröffentlichungsmodus selbst hat nicht das Problem von synchronen und asynchronen Aufrufen, aber im Knoten werden emittierte Aufrufe meist asynchron mit der Ereignisschleife ausgelöst. Dieser Modus wird häufig verwendet, um die Geschäftslogik zu entkoppeln. Event -Publisher müssen weder auf die registrierte Rückruffunktion achten, noch müssen sie auf die Anzahl der Rückruffunktionen achten. Daten können flexibel über Nachrichten übertragen werden.
Die Vorteile dieses Musters sind: 1. leicht zu verstehen; 2. nicht mehr auf eine Rückruffunktion beschränkt.
Wenn es um schlechte Dinge geht: 1. Sie müssen die Klassenbibliothek verwenden; 2. Die Reihenfolge der Ereignisse und Rückruffunktionen ist sehr wichtig
Die Codekopie lautet wie folgt:
var img = document.querySelect (#ID);
img.addeventListener ('last', function () {
// Das Bild ist geladen
......
});
img.addeventListener ('error', function () {
// Etwas lief schief
......
});
Es gibt zwei Probleme mit dem obigen Code:
A. IMG wurde tatsächlich geladen und die Last -Rückruffunktion ist zu diesem Zeitpunkt gebunden. Infolgedessen wird der Rückruf nicht ausgeführt, aber er hofft immer noch, die entsprechende Rückruffunktion auszuführen.
Die Codekopie lautet wie folgt:
var img = document.querySelect (#ID);
Funktion load () {
...
}
if (img.com plete) {
laden();
} anders {
img.addeventListener ('last', last);
}
img.addeventListener ('error', function () {
// Etwas lief schief
......
});
B. Ausnahmen können nicht gut umgehen
Schlussfolgerung: Der Ereignismechanismus ist am besten geeignet, um mit wiederholten Ereignissen auf demselben Objekt umzugehen, und es ist nicht erforderlich, das Ereignis zu berücksichtigen, bevor die Rückruffunktion gebunden ist.
1.3 Asynchrone Kontrollbibliothek
Die aktuellen asynchronen Bibliotheken umfassen hauptsächlich Q, wann.js, Win.js, rsvp.js usw.
Das Merkmal dieser Bibliotheken ist, dass der Code linear ist und von oben nach unten im Einklang mit natürlichen Gewohnheiten geschrieben werden kann.
Die schlechten Dinge unterscheiden sich auch in Stilen, die unpraktisch sind, um die Lernkosten zu lesen und zu erhöhen.
1.4 Versprechen
Versprechen wird als Versprechen in Chinesisch übersetzt. Persönlich wird nach Abschluss asynchron ein externes Ergebnis (Erfolg oder Misserfolg) und versprechen, dass sich das Ergebnis nicht mehr ändert. Mit anderen Worten, Promise spiegelt den endgültigen Rückgabeergebniswert einer Operation wider (ein Versprechen repräsentiert den eventuellen Wert, der aus dem einzigen Abschluss einer Operation zurückgegeben wird). Gegenwärtig wurde Versprechen in die ES6 -Spezifikation eingeführt, und fortschrittliche Browser wie Chrome und Firefox haben diese native Methode intern implementiert, was sehr bequem zu verwenden ist.
Das Folgende sind die Merkmale des Versprechens aus den folgenden Aspekten:
1.4.1 Status
Es enthält drei Staaten: anhängig, erfüllt und abgelehnt. Die drei Staaten können nur zwei Übergänge (ausstehend ---> erfüllt, ausstehend-> abgelehnt) erfahren, und der Übergang des Staates kann nur einmal auftreten.
1.4.2 dann Methode
Mit der damaligen Methode wird die Rückruffunktion angeben, nachdem das asynchrone Ereignis abgeschlossen ist.
Diese Methode kann als Seelenmethode des Versprechens bezeichnet werden, was Versprechen voller Magie macht. Es gibt mehrere spezifische Manifestationen wie folgt:
a) Dann gibt die Methode das Versprechen zurück. Dies ermöglicht serielle Operationen mehrerer asynchroner Operationen.
In Bezug auf den gelben Kreis 1 in der obigen Abbildung ist die Wertverarbeitung ein komplizierterer Teil des Versprechens. Die Wertverarbeitung ist in zwei Situationen unterteilt: Versprechenobjekt und nicht-promise-Objekt.
Wenn der Wert kein Versprechentyp ist, verwenden Sie einfach den Wert als Parameterwert der Auflösung des zweiten Versprechens. Wenn es sich um einen Versprechen -Typ handelt, werden der Status und die Parameter von Promise2 vollständig vom Wert bestimmt. Es kann angenommen werden, dass Promsie2 eine Wertpuppe ist und Versprechen2 nur eine Brücke ist, die unterschiedliche Asynchronen verbindet.
Die Codekopie lautet wie folgt:
Promise.Prototype.Then = Funktion (überfüllte, onrejected) {
Neues Versprechen zurückgeben (Funktion (Resolve, Ablehnung) {// Das Versprechen hier ist als Promise2 gekennzeichnet2 markiert2
handhaben({
auffüllte: erläutert,
onrejected: onrejected,
Entschlossenheit: Beheben Sie,
Ablehnung: Ablehnung
})
});
}
Funktion Handle (aufgeschoben) {
var handlefn;
if (state === 'erfüllt') {
handlefn = deferred.onFoFilled;
} else if (state === 'abgelehnt') {
handlefn = deferred.onrejected;
}
var ret = handlefn (Wert);
aufgeschoben.Resolve (ret); // Beachten Sie, dass die Entschlossenheit zu diesem Zeitpunkt die Entschlossenheit von Promise2 ist
}
Funktionsauflösung (Val) {
if (val && typeof val.then === 'Funktion') {
Val.Then (Resolve); // Wenn Val ein Versprechenobjekt oder ein Klassenversprechensobjekt ist, wird der Status von Promise2 vollständig von Val bestimmt
zurückkehren;
}
if (callback) {// Rückruf ist die angegebene Rückruffunktion
Rückruf (Val);
}
}
b) Die Umwandlung zwischen mehreren verschiedenen asynchronen Bibliotheken wird implementiert.
Es gibt ein Objekt, das in Asynchronous genannt wird, das sich auf ein Objekt mit der damaligen Methode bezieht. Solange ein Objektobjekt die damalige Methode hat, kann es beispielsweise konvertiert werden:
Die Codekopie lautet wie folgt:
var deferred = $ ('aa.ajax'); // !! aufgeschoben.then === true
var p = drequent.resolve (aufgeschoben);
p.then (......)
1.4.3 CommonJs Versprechen/eine Spezifikation
Derzeit gibt es Versprechen/A und Versprechen/A+ Spezifikationen für die Spezifikationen bezüglich des Versprechens, was zeigt, dass die Umsetzung von Versprechen sehr kompliziert ist.
Die Codekopie lautet wie folgt:
Dann (FulstedHandler, abgelehnt, progreshatler)
1.4.4 Notizen
Die Rückruffunktion in einem Versprechen teilt den Wert. In der Ergebnisverarbeitung wird der Wert als Parameter an die entsprechende Rückruffunktion übergeben. Wenn der Wert ein Objekt ist, achten Sie darauf, den Wert nicht einfach zu ändern.
Die Codekopie lautet wie folgt:
var p = drequent.resolve ({x: 1});
p.then (Funktion (val) {
console.log ('erster Rückruf:'+val.x ++);
});
p.then (Funktion (val) {
console.log ('zweiter Rückruf:' + val.x)
})
// Erster Rückruf: 1
// zweiter Rückruf: 2
1.5 Generator
Alle oben genannten Methoden basieren auf der Rückruffunktion, um asynchrone Operationen zu vervollständigen, und sie sind nichts weiter als die Rückruffunktion zu verkörpern. ES6 schlägt Generator vor, der Möglichkeiten zur Lösung asynchroner Operationen hinzufügt und basierend auf Rückruffunktionen nicht mehr abgeschlossen ist.
Das größte Merkmal des Generators besteht darin, dass er innehalten und neu starten kann, was für die Lösung asynchroner Operationen sehr förderlich ist. Durch die Kombination von Generator -Pause mit der Ausnahmebehandlung von Promise kann das asynchrone Programmierungsproblem eleganter gelöst werden. Spezifische Implementierungsreferenz: Kyle Simpson
2. Probleme mit der asynchronen Programmierung
2.1 Ausnahmebehandlung
A) Zu den asynchronen Ereignissen gehören zwei Links: Ausgabe asynchroner Anfragen und Verarbeitungsergebnisse. Diese beiden Links werden über Ereignisschleifen verbunden. Wenn Sie dann versuchen, eine Ausnahme -Capture durchzuführen, müssen Sie sie erfassen.
Die Codekopie lautet wie folgt:
versuchen {
AsyncEvent (Rückruf);
} catch (err) {
......
}
Der obige Code kann die Ausnahme im Rückruf nicht aufnehmen und kann die Ausnahme im Anforderungsvorgang nur erhalten. Dies hat Probleme: Wenn die Ausgabe der Anfrage und die Anfrage von zwei Personen abgeschlossen sind, gibt es bei der Behandlung von Ausnahmen Probleme?
b) Versprechen implementiert die Ausnahmeregelung, die einige Vorteile bringt, um sicherzustellen, dass der Code in den tatsächlichen Projekten nicht blockiert wird. Wenn es jedoch viele asynchrone Ereignisse gibt, ist es nicht leicht herauszufinden, welches asynchrone Ereignis eine Ausnahme erzeugt.
Die Codekopie lautet wie folgt:
// Szenenbeschreibung: Anzeigen von Preisalarminformationen in CRM, einschließlich Wettbewerbsinformationen. Es dauert jedoch lange, bis die Wettbewerbsinformationen erhalten werden. Um eine langsame Abfrage zu vermeiden, teilt der Backend eine Platte in zwei Teile auf, um sie separat zu erhalten.
// Schritt 1: Zusätzlich zu Wettbewerbsinformationen Preisalarminformationen erhalten
Funktion getPricealarmData () {
Neues Versprechen zurückgeben (Funktion (Resolve) {
Y.io (url, {
Methode: 'Get',
Daten: Parameter,
on: function () {
Erfolg: Funktion (ID, Daten) {
auflösen (alarmdata);
}
}
});
});
}
// Gehen Sie nach Erhalt der Alarminformationen, um die Wettbewerbsinformationen zu erhalten
GetPriceArarmData (). Dann (Funktion (Daten) {
// Datenwiedergabe zusätzlich zu Wettbewerbsinformationen
Render (Daten);
Neues Versprechen zurückgeben (Funktion (Resolve) {
Y.io (url, {
Methode: 'Get',
Daten: {Alarmlist: Daten},
on: function () {
Erfolg: Funktion (ID, CompData) {
Resolve (compData);
}
}
});
});
}) // nach Erhalt aller Daten und Rendering der Wettbewerbsinformationen
.then (Funktion (Daten) {
// Die Gebotsinformationen rendern
Rendern (Daten)
}, function (err) {
// Ausnahmebehandlung
console.log (err);
});
Der obige Code kann in Folgendes konvertiert werden:
Die Codekopie lautet wie folgt:
versuchen{
// andere Alarminformationen als Wettbewerb erhalten
var alarmdata = alarmdataexceptCompare ();
Render (alarmdata);
// Anfrage von Wettbewerbsinformationen basierend auf Alarminformationen
var verglichenata = getCompareinfo (alarmdata);
Render (verglichen);
} catch (err) {
console.log (err.message);
}
Im obigen Beispiel wird die Ausnahme am Ende behandelt, so dass wir nicht genau wissen, welches Ereignis eine Ausnahme in einem bestimmten Link auftritt.
2.2 JQuery.Desferred Problem
Asynchrone Operationen werden ebenfalls in JQuery implementiert, entsprechen jedoch nicht den Versprechen/A+ -Pecialationen in der Implementierung und spiegeln sich hauptsächlich in den folgenden Aspekten wider:
A. Anzahl der Parameter: Standardversprechen kann nur einen Parameter akzeptieren, während JQuery mehrere Parameter übergeben kann
Die Codekopie lautet wie folgt:
Funktion asyncinjQuery () {
var d = new $ .deferred ();
setTimeout (function () {
d.resolve (1, 2);
}, 100);
Rückkehr d.Promise ()
}
asyncinjQuery (). Dann (Funktion (val1, val2) {
console.log ('output:', val1, val2);
});
// Ausgabe: 1 2
B. Umgang mit Ausnahmen in der Ergebnisverarbeitung
Die Codekopie lautet wie folgt:
Funktion asyncinpromise () {
Neues Versprechen zurückgeben (Funktion (Resolve) {
setTimeout (function () {
var JSONSON = '{"Name": "mt}';
Resolve (JSONSON);
}, 100);
});
}
asyncinpromise (). Dann (Funktion (val) {
var d = json.Parse (val);
console.log (d.name);
}). Dann (null, function (err) {
console.log ('Fehler anzeigen:' + err.message);
});
// Fehler anzeigen: Unerwartetes Ende der Eingabe
Funktion asyncinjQuery () {
var d = new $ .deferred ();
setTimeout (function () {
var JSONSON = '{"Name": "mt}';
d.resolve (Jomin);
}, 100);
Rückkehr d.Promise ()
}
asyncinjQuery (). Dann (Funktion (val) {
var d = json.Parse (val);
console.log (d.name);
}). Dann (Funktion (v) {
console.log ('Erfolg:', v.Name);
}, function (err) {
console.log ('Fehler anzeigen:' + err.message);
});
// Uncortn SyntaxError: Unerwartetes Ende der Eingabe
Daraus ist zu erkennen, dass das Versprechen das Ergebnis der Rückruffunktion verarbeitet, die Ausnahmen während der Ausführung der Rückruffunktion erfassen kann, aber jQuery.verdeter kann nicht.