Maison > interface Web > js tutoriel > le corps du texte

Analyse approfondie des objets de promesse (avec exemples)

不言
Libérer: 2018-11-23 14:49:00
avant
2197 Les gens l'ont consulté

Cet article vous apporte une analyse approfondie des objets promis (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

Asynchrone dans js a été initialement implémenté à l'aide de fonctions de rappel, donc si asynchrone est imbriqué, il y aura un enfer de rappel, rendant le code difficile à lire et à maintenir. Plus tard, es6 est apparu. L'utilisation de promesses résout le problème de. rappel en enfer. Nous allons maintenant écrire nous-mêmes le code pour mettre en œuvre la promesse, afin que nous puissions avoir une compréhension approfondie du mécanisme de fonctionnement de la promesse et être plus à l'aise avec l'utilisation des promesses à l'avenir. Avant de commencer, vous pouvez jeter un œil au site officiel de promise/A+

Regardons d'abord l'utilisation de promise

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);
});
Copier après la connexion

Impression sur console
1
. ..1 secondes plus tard
2

Analysons d'abord le code ci-dessus et posons quelques questions
1 Le premier paragraphe contient à la fois une résolution et un rejet, mais seulement 1 est affiché Pourquoi ?
2. Comment res in obtient-il alors la valeur en résolution ?
3. Comment la promesse réalise-t-elle les appels en chaîne ?

Machine à états

Il existe un concept de machine à états dans la promesse Parlons d'abord de la raison pour laquelle il existe un concept de machine à états, car l'état de la promesse change dans une direction et a trois états. : ending , fullfilled, rejeté, et ces trois états ne peuvent être que sous la forme ending->fullfilled ou ending->rejected, ce qui signifie qu'une fois fullfilled exécuté, rejeté ne sera pas exécuté. Ceci explique la première question ci-dessus.

Jetons un coup d'œil au code complet de l'implémentation spécifique

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;
        }
    }
}
Copier après la connexion

Exécutez l'exemple suivant

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);
});
Copier après la connexion

Impression sur console
...1 s plus tard
1
...1s plus tard
2
...1s plus tard
3
Cela montre qu'il n'y a pas de problème avec la mise en œuvre ci-dessus
Mais il y a un autre problème , qui est la boucle d'événement Problèmes de séquence, par exemple, l'exécution du code suivant

new Promise((resolve) => {
    resolve();
})
.then(() => {
    console.log('1');
})
.then(() => {
    console.log('2');
});
console.log('3');
Copier après la connexion

ne génère pas 3,1,2 comme prévu, mais génère 1,2,3 La raison est que notre promesse. est dans le main Si le thread n'est pas dans la file d'attente des tâches suivante, vous pouvez ajouter settimeout pour résoudre ce problème, mais c'est juste pour nous permettre de mieux comprendre la séquence d'exécution. Cependant, en fait, les promesses appartiennent aux microtâches, et settimeout appartient. aux macrotâches, c'est toujours pas pareil

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal