Heim > Artikel > Web-Frontend > Eingehende Analyse von Versprechensobjekten (mit Beispielen)
Dieser Artikel bietet Ihnen eine ausführliche Analyse der Versprechensobjekte (mit Beispielen). Freunde in Not können darauf verweisen.
Asynchron in js wurde ursprünglich mit Rückruffunktionen implementiert. Wenn Asynchron verschachtelt ist, kommt es zu einer Rückrufhölle, die das Lesen und Warten des Codes erschwert. Später wurde es6 verwendet, um das Problem zu lösen Rückruf Hölle. Jetzt werden wir den Code selbst schreiben, um das Versprechen umzusetzen, damit wir den Funktionsmechanismus des Versprechens tiefgreifend verstehen und Versprechen in Zukunft besser nutzen können. Bevor Sie beginnen, können Sie einen Blick auf die offizielle Website von Promise/A+ werfen
Schauen wir uns zunächst die Verwendung von Promise an
new Promise((resolve,reject)=>{ resolve(1); reject(11); }).then(res=>{ console.log(res); setTimeout(()=>{ return new Promise((resolve,reject)=>{ resolve(2) }) },1000) }).then(res2=>{ console.log(res2); });
Konsolendruck
1
...1s später
2
Lass uns zuerst den obigen Code analysieren und ein paar Fragen stellen
1. Der erste Absatz enthält sowohl „Auflösen“ als auch „Ablehnen“, aber nur 1 wird ausgegeben.
2. Wie erhält „res in“ dann den Wert in „resolution“?
3. Wie führt ein Versprechen zu einer Kettenaufforderung?
Es gibt ein Konzept einer Zustandsmaschine im Versprechen. Lassen Sie uns zunächst darüber sprechen, warum es ein Konzept der Zustandsmaschine gibt, da sich der Zustand des Versprechens in eine Richtung ändert und drei Zustände hat : ausstehend, erfüllt, abgelehnt, und diese drei Zustände können nur in der Form „ausstehend-> erfüllt“ oder „ausstehend-> abgelehnt“ vorliegen, was bedeutet, dass „abgelehnt“ nach der Ausführung von „ausgefüllt“ nicht ausgeführt wird. Dies erklärt die erste Frage oben.
Sehen wir uns den vollständigen Code der spezifischen Implementierung an
const PENDING = 'PENDING'; const FULLFILLED = 'FULLFILLED'; const REJECTED = 'REJECTED'; class Promise{ constructor(fn){ this.status = PENDING;//状态 this.data = undefined;//返回值 this.defercb = [];//回调函数数组 //执行promise的参数函数,并把resolve和reject的this绑定到promise的this fn(this.resolve.bind(this),this.reject.bind(this)); } resolve(value){ if(this.status === PENDING){ //只能pending=>fullfied this.status = FULLFILLED; this.data = value; this.defercb.map(item=>item.onFullFilled()); } } reject(value){ if(this.status === PENDING){ //只能pending=>rejected this.status = REJECTED; this.data = value; this.defercb.map(item=>item.onRejected()); } } then(resolveThen,rejectThen){ //如果没有resolveThen方法,保证值可以穿透到下一个then里有resolveThen的方法中 resolveThen = typeof resolveThen === 'function' ? resolveThen : function(v) {return v}; rejectThen = typeof rejectThen === 'function' ? rejectThen : function(r) {return r}; //返回的都是promise对象,这样就可以保证链式调用了 switch(this.status){ case PENDING: return new Promise((resolve,reject)=>{ const onFullFilled = () => { const result = resolveThen(this.data);//这里调用外部then的resolveThen方法,将值传回去 //如果返回值是promise对象,执行then方法,取它的结果作为新的promise实例的结果,因为this.data会重新赋值 result instanceof Promise && result.then(resolve,reject); } const onRejected = ()=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); } this.defercb.push({onFullFilled,onRejected}); }); break; case FULLFILLED: return new Promise((resolve,reject)=>{ const result = resolveThen(this.data); result instanceof Promise && result.then(resolve,reject); resolve(result); }) break; case REJECTED: return new Promise((resolve,reject)=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); reject(result) }) break; } } }
Führen Sie das folgende Beispiel aus
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }).then((res2) => { console.log(res2); return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 1000); }); }).then((res3) => { console.log(res3); return new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 1000); }); }).then((res4) => { console.log(res4); });
Konsolendruck
...1 Sekunde später
1
...1s später
2
...1s später
3
Es zeigt, dass es kein Problem mit der obigen Implementierung gibt
Aber es gibt ein anderes Problem, nämlich das Reihenfolge der Ereignisschleife. Wenn Sie beispielsweise den folgenden Code ausführen:
new Promise((resolve) => { resolve(); }) .then(() => { console.log('1'); }) .then(() => { console.log('2'); }); console.log('3');
, wird nicht wie erwartet 3,1,2 ausgegeben, sondern 1,2,3. Der Grund dafür ist, dass sich unser Versprechen im Hauptthread befindet und nicht in der nächsten Task-Warteschlange kann settimeout hinzugefügt werden, um dieses Problem zu lösen. Dies dient jedoch nur dazu, die Ausführungssequenz besser zu verstehen. Tatsächlich gehören Versprechen jedoch zu Mikroaufgaben, während settimeout zu Makroaufgaben gehört Aufgaben, die immer noch anders sind
Das obige ist der detaillierte Inhalt vonEingehende Analyse von Versprechensobjekten (mit Beispielen). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!