Heim > Web-Frontend > js-Tutorial > Eingehende Analyse von Versprechensobjekten (mit Beispielen)

Eingehende Analyse von Versprechensobjekten (mit Beispielen)

不言
Freigeben: 2018-11-23 14:49:00
nach vorne
2217 Leute haben es durchsucht

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);
});
Nach dem Login kopieren

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?

Zustandsmaschine

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;
        }
    }
}
Nach dem Login kopieren

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);
});
Nach dem Login kopieren

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');
Nach dem Login kopieren

, 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!

Verwandte Etiketten:
Quelle:segmentfault.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage