当前位置:网站首页>Analysez l'objet promise avec le noyau dur (Connaissez - vous les sept API communes obligatoires et les sept questions clés?)

Analysez l'objet promise avec le noyau dur (Connaissez - vous les sept API communes obligatoires et les sept questions clés?)

2022-04-23 18:13:00 Xiaojie Learning Front End

Table des matières

Un.、PromiseCompréhension et utilisation

PromiseLe concept de

PromiseUtilisation de

Rappel des problèmes de l'enfer

Solutions

PromiseUtilisation de base de

PromiseExpérience initiale de la pratique

fsModule lire le fichier

Utiliser promise Encapsulation ajax Demande asynchrone

promise Propriétés de l'état de l'objet

promise Attribut de valeur du résultat de l'objet

Cas mineurs

2.、Promise API

Promise Constructeur: Promise (excutor) {}

Promise.prototype.then()

Promise.prototype.catch()

Promise.resolve() 

Promise.reject()  

Promise.all()    

Promise.race() 

Trois、PromisePrincipales questions 

1. Comment modifier l'état d'un objet

2.Possibilité d'effectuer plusieurs rappels

3. Problème de séquence entre le changement d'état et l'exécution du rappel

4.then La méthode renvoie les résultats par quelle décision  

5.Concaténation de plusieurs tâches

6.Pénétration anormale

7. Comment finir PromiseChaîne 


Un.、PromiseCompréhension et utilisation

PromiseLe concept de

Promise Est une solution de programmation asynchrone, Et quelle était notre solution précédente ?C'est vrai,Est la fonction de rappel.Promise Plus raisonnable et plus puissant que ça. .

Cette explication n'est pas assez claire ,C'est...PromiseQu'est - ce que c'est? 

Simplement un conteneur,Il contient un événement qui ne se termine que dans le futur(Généralement une opération asynchrone)Les résultats de.

Un discours populaire,Promise C'est une promesse. , C'est une promesse pour l'avenir. , Les promesses ne sont pas toujours faites ( Comme si tu avais promis à ta copine de lui acheter un sac dans le futur , Je voulais juste m'occuper d'abord , Je ne sais pas si je l'achèterai plus tard. ), Mais que ce soit fait ou non, il y aura un résultat .

PromiseUtilisation de

Promise Est une solution de programmation asynchrone, Utilisé principalement pour résoudre le problème du rappel de l'enfer , Réduit efficacement la nidification des callbacks .

Grammaticalement parlant:PromiseEst un constructeur

Fonctionnellement parlant:Promise L'objet est utilisé pour encapsuler une opération asynchrone et obtenir son succès /Valeur de retour échouée

Commençons par penser à ce qui est asynchrone  

fsOpérations de fichiers    Fonctionnement de la base de données   ajaxAction demandée   Minuterie

Il y a des opérations asynchrones dessus

fsOpérations de fichiers require('fs').readFile('./xiaojie.txt',(err,data)=>{})
Fonctionnement de la base de données   $.get('/server',(data)=>{})
Minuterie   setTimeout(() => {}, 2000);

InpromiseAvant, Lorsque nous effectuons des opérations asynchrones , C'est fait de façon purement Callback , Alors pourquoi on l'utilise? promiseEt alors?, Vous ne pouvez pas utiliser la fonction de rappel  

Attention!,C'est le plus important.,L'interview est obligatoire.

  Parce quePromisePrise en charge des appels en chaîne,Peut résoudre le problème de l'enfer de rappel  

Rappel des problèmes de l'enfer

Qu'est - ce que l'enfer du rappel?   Pourquoi le résoudre?  PromiseComment ça s'est passé? 

On va régler ça un par un :

D'abord, regardons ce code , Nous voulons produire des chiffres en trois étapes , Une seconde à la fois , Alors nous devons le faire :

setTimeout(function () {
    console.log(111);
    setTimeout(function () {
        console.log(222);
        setTimeout(function () {
            console.log(333);
        }, 1000);
    }, 1000);
}, 1000);

Nidification de code, Dans un programme complexe , Est très difficile à lire et à gérer les exceptions , Parce qu'à chaque niveau, nous avons besoin d'une exception pour les erreurs , Peut écrire beaucoup de code dupliqué et rendre le format d'indentation très encombrant , Lorsque trop de couches imbriquées ,Ça va arriver.“Rappel Hell”. Cela montre à quel point il est important d'écrire le Code d'une nouvelle façon .Avecpromise Comment faire face à ce genre de problèmes , Ce serait plus approprié. .

Solutions

  promiseAppel en chaîne  

new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(111);
        resolve();
    }, 1000);
}).then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(222);
            resolve();
        }, 1000);
    });
}).then(() => {
    setTimeout(() =>{
        console.log(333);
    }, 1000);
});

Le résultat final est le même , Et changerait l'écriture des énoncés de code imbriqués en écriture séquentielle , Mais ne change pas le processus asynchrone qu'il exécute ,C'est exactement ça.promise Le rôle et les avantages de la méthode . 

PromiseUtilisation de base de

ES6 Le règlement,Promise Est un constructeur, C'est le constructeur qui peut instancier l'objet .

promise Les paramètres doivent être acceptés lors de l'Instanciation de l'objet , Ce paramètre est la valeur d'un type de fonction

Les deux paramètres de cette fonction sont resolve Et reject .

resolve C'est la solution. ,reject C'est un refus. .

Les deux sont des données de type fonction

Appelé lorsque la tâche asynchrone est réussie resolve, Appelé lorsque la tâche asynchrone échoue reject

Le code suivant crée unPromiseExemple.

const p = new Promise((resolve, reject) => {
  // ... some code
    if (/* Opération asynchrone réussie */){
        resolve(value);
    } else {
        reject(error);
    }
});

  resolve() Après l'appel ,Vous pouvezpromiseObjet(p)L'état est réglé à succès  

  reject() Au contraire.,Après l'appel,Vous pouvezpromiseObjet(p) L'état de est défini à l'échec   

Nous avons créépromise Appelé après l'Instance thenMéthodes, Il a besoin de deux paramètres pour l'exécuter ,Et les deux arguments sont des valeurs de type fonction

p.then((value) => {},(error) => {});

Le premier paramètre est le rappel lorsque l'objet réussit , Le deuxième paramètre est le rappel lorsque l'objet échoue .

Ces deux paramètres sont optionnels,Il n'est pas nécessaire de fournir.Ils acceptent tous Promise La valeur sortante de l'objet comme paramètre.
En langage courant,Sipromise La première fonction de rappel est exécutée lorsque l'état de l'objet est réussi , Si l'état échoue, exécutez la deuxième fonction de rappel

PromiseExpérience initiale de la pratique

Nous n'allons pas commencer l'explication PromiseDiversAPIEt principes, Commencez par deux applications pratiques ,Simple expériencePromise.

fsModule lire le fichier

Ceci nécessite notre installation node.jsEnvironnement,fs La fonction du module est de lire et d'écrire sur le disque dur de l'ordinateur

Notre cas exige que :

Lire dans le répertoire courantnba.txtContenu du document:

  Forme traditionnelle de la fonction de rappel : 

//IntroductionfsModule
const fs = require('fs');
fs.readFile('./nba.txt', (err, data) => {
    // En cas d'erreur Lance une erreur
    if(err)  throw err;
    // Exporter le contenu du fichier sans erreur 
    console.log(data.toString());
});
PS D:\Répertoire des utilisateurs\Desktop\home\html (2)\4.20> node zyj.js
 Champion des guerriers 

Dans ce cas, notrenba.txt Le contenu est sorti.

  PromiseForme de l'emballage: 

//Encapsule une fonction mineReadFile Lire le contenu du fichier
//Paramètres:  path  Chemin du fichier
//Retour:  promise Objet

function mineReadFile(path){
   return new Promise((resolve, reject) => {
       //Lire le fichier
       require('fs').readFile(path, (err, data) =>{
           //Jugement
           if(err) reject(err);
           //Succès
           resolve(data);
       });
   });
}

mineReadFile('./nba.txt')
.then(value=>{
   //Contenu du fichier de sortie
   console.log(value.toString());
}, error=>{
   console.log(error);
});

Si ça marchedataJuste un.bufferBesointostring Comment le convertir en chaîne , Imprimer l'objet incorrect en cas d'erreur

Quand la sortie est normale :

PS D:\Répertoire des utilisateurs\Desktop\home\html (2)\4.20> node zyj.js
 Champion des guerriers 

Nous avons délibérément mal tracé le chemin , Voir ce que les erreurs produisent :

PS D:\Répertoire des utilisateurs\Desktop\home\html (2)\4.20> node zyj.js
[Error: ENOENT: no such file or directory, open 'D:\Répertoire des utilisateurs\Desktop\home\html (2)\4.20\na.txt'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'D:\\Répertoire des utilisateurs\\Desktop\\home\\html (2)\\4.20\\na.txt'
}

La sortie esterror Contenu de cet objet d'erreur

Utiliser promise Encapsulation ajax Demande asynchrone

<script >
/*Cheveux réutilisables ajax Fonction demandée: xhr + promise*/
function promiseAjax(url) {
     return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open("GET", url);
            xhr.send();
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== 4) return;
              // Demande acceptée, Appelez resolve(value)
              if (xhr.status >= 200 && xhr.status < 300) {
                resolve(xhr.response);
              } else { // La demande a échoué, Appelez reject(reason)
                reject(xhr.status);
              }
            }
          })
        }
promiseAjax('http://www.liulongbin.top:3006/api/getbooks').then(data => {
           console.log('Afficher les données de succès', data)
        },
        error => {
           alert(error)
        }) 
</script>

Résultats obtenus:

Quand nous avons délibérément mal tapé l'adresse :

promise Propriétés de l'état de l'objet

Promise L'état de l'objet n'est pas affecté par l'extérieur.Promise L'objet a trois états:
  pending (En cours)、fulfilled (A réussi) Et rejected (Échec).

Dès que l'état change,Ça ne changera plus.,Ce résultat peut être obtenu à tout moment.

PromiseC'est exact. Changement d'état de l'image ,Il n'y a que deux possibilités.:De pending Devient fulfilled(resolved)Et de pending Devient rejected.

Tant que ces deux choses arrivent,L'état se solidifie.,Ça ne changera plus.,Ce résultat sera maintenu.

Seuls les résultats des opérations asynchrones,Vous pouvez décider quel état est actuellement,Aucune autre action ne peut changer cet état.Et ça aussi.PromiseL'origine de ce nom,C'est ce que ça veut dire en anglais.“Engagements”,Indique que d'autres moyens ne peuvent être modifiés.

Si le changement a déjà eu lieu,Tu as raison.PromiseObjet ajouter une fonction de rappel,Et vous obtiendrez ce résultat immédiatement.Ceci et l'événement(Event)C'est complètement différent.,Les événements sont caractérisés par:,Si vous le manquez,Et écoute.,Il n'y a pas de résultat..

promise Attribut de valeur du résultat de l'objet

C'est promise Une autre propriété dans l'objet instance [promiseResult] ,Les tâches asynchrones sont sauvegardées [Succès/Échec] Les résultats de

resolveEtreject Deux méthodes sont disponibles pour modifier les propriétés résultantes de l'objet instance , Personne d'autre qu'eux ne peut changer

Cas mineurs

À droitePromise J'ai une idée. ,Regardons le code ci - dessous:

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

Analyse:

Dans le code ci - dessus,timeout La méthode renvoie unPromiseObjet instance,Représente un résultat qui ne se produira qu'après un certain temps.Temps écoulé(msParamètres)Plus tard,  Le minuteur appelle resolve(), Et que les résultats (done)Ça arrive, Après l'appel ,Vous pouvezpromiseObjet(p)L'état est réglé à succès , Si son état change, il déclenche thenFonction de rappel liée à la méthode, La valeur des résultats transmis (done)Sortie.

2.、Promise API

Promise Constructeur: Promise (excutor) {}

(1) executor Fonctions: Actionneur (resolve, reject) => {}

(2) resolve Fonctions: La fonction que nous appelons lorsque la définition interne est réussie value => {}

(3) reject Fonctions: La fonction que nous appelons lorsque la définition interne échoue reason => {}

Points saillants:executor Il sera là. Promise Appel de synchronisation interne immédiat 

Regardons ce code

let p = new Promise(function(resolve, reject) {
  console.log('jack');
  resolve();
});

p.then(value=> {
  console.log('andy');
});

console.log('Hi!');

// jack
// Hi!
// andy

Dans le code ci - dessus,Promise Exécuter immédiatement après la création,Donc la première sortie est 'jack'.Et puis,thenFonction de rappel spécifiée par la méthode,Toutes les tâches de synchronisation du script actuel ne seront pas exécutées avant,Donc la sortie 'Hi','andy' La sortie finale.

En fait,, Les points de connaissance relatifs à ce résultat opérationnel sont [ Macro - tâche et micro - tâche ]  , Peigné séparément en dessous :

  • Tâche macro: setTimeout , setInterval , Ajax , DOMÉvénements
  • Microtâche: Promise async/await
  • Les micro - tâches sont exécutées plus tôt que les macro - tâches(Souviens - toi d'abord.)

Voici une question d'entrevue :

console.log(100);

setTimeout(()=>{
    console.log(200);
})

setTimeout(()=>{
    console.log(201);
})

Promise.resolve().then(()=>{
    console.log(300);
})

console.log(400);

// 100 400 300 200 201

Tout le monde a fait ce qu'il fallait? , Si ce n'est pas bien fait ,Encore une fois.JSMécanisme de fonctionnement C'est facile à comprendre :

  • Toutes les tâches de synchronisation sont exécutées sur le fil principal,Ligne en une pile d'exécution.
  • En plus du fil principal,Il y a encore une file d'attente,Tant que la tâche asynchrone a un résultat d'exécution,Juste un marqueur temporel dans la file d'attente de la Mission.
  • Le fil principal accomplit toutes les tâches(Effectuer un nettoyage de pile),Et lire la file d'attente de la Mission,Exécuter d'abord la file d'attente des micro - tâches dans la file d'attente des macro - tâches.
  • Répétez les trois étapes ci - dessus.

Promise.prototype.then()

thenLa méthode est définie dans l'objet prototypePromise.prototypeOui..Son rôle est de Promise Fonction de rappel lorsque l'état d'ajout de l'Instance change

then La méthode renvoie un nouveau PromiseExemple 

thenLa méthode renvoie un nouveauPromiseExemple(Attention!,Pas celui - là.PromiseExemple).Il est donc possible d'écrire en chaîne,C'est - à - dire:thenAppelez l'autre après la méthodethenMéthodes.

let p = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, 'jack'); 
}); 
p.then(value => {
  console.log(value); 
  return 'andy';
}).then(value => console.log(value));
//jack
//andy

then()La méthode renvoie un nouveauPromiseObjet, Alors...then Vous pouvez continuer avec un then Méthode d'appel en chaîne , Sithen La fonction de rappel de la méthode a des données de retour , Alors ces données seront utilisées comme prochain thenParamètres de la fonction de rappel pour, Ce point de connaissance concerne les appels en chaîne ,InPromise Questions clés la cinquième série de tâches multiples est expliquée en détail . Faites un tour d'horizon ici .

Chaînethen, Il attendra le dernierPromise Un changement d'état est appelé

then La fonction de rappel peut également renvoyer un PromiseObjet, C'est l'heure de l'écrasement. then De retour PromiseObjet,Cette dernière fonction de rappel,Je vais attendre.PromiseL'état de l'objet a changé,Sera appelé.

let p = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, 'jack'); 
}); 
p.then(value => {
  console.log(value); 
  return new Promise((resolve,reject) => {
    setTimeout(resolve,1000,'andy');
  });
}).then(value => console.log(value));
//jack
//andy

Dans le code ci - dessus,Le premierthenFonction de rappel spécifiée par la méthode,Retour à un autrePromiseObjet.À ce moment - là,,DeuxièmethenFonction de rappel spécifiée par la méthode,J'attendrai ce nouveauPromiseL'état de l'objet a changé.

Parce que la deuxième fonction de rappel a un minuteur , Donc une seconde plus tard, l'état devient resolved,Deuxièmethen La méthode ne s'exécute pas tant que l'état n'a pas changé logDéclarations de sortie

Promise.prototype.catch()

Promise.prototype.catch()La méthode est: .then(null, rejection) Ou .then(undefined, rejection) Alias de,Utilisé pour spécifier la fonction de rappel en cas d'erreur.

let p = new Promise((resolve, reject) => { 
  reject('what is the matter');
}); 
p.catch(error => {
  console.log(error);
})
//what is the matter

SiPromise L'état de l'objet devientrejected,Appelle catch() Fonction de rappel spécifiée par la méthode,Gérer cette erreur.

let p = new Promise((resolve, reject) => { 
  throw new Error('Erreur lancée')
}); 
p.catch(error => {
  console.log(error);
})
//Error: Erreur lancée

Dans le code ci - dessus,PromiseLancer une erreur,Il sera aussi catch() Capture de la fonction de rappel spécifiée par la méthode.

  Ce qui est remarquable, c'est que:Si Promise L'état est devenu resolved ,Une autre erreur est invalide. 

let p = new Promise((resolve, reject) => { 
  resolve('success');
  throw new Error('Erreur lancée')
}); 
p.then(value => {
  console.log(value);
}).catch(error => {
  console.log(error);
})
//success

Dans le code ci - dessus, Lancer une erreur dans resolve Après la Déclaration, Alors on ne sera pas pris. ,égal à ne pas lancer.Parce que Promise Une fois que l'état de,Pour toujours.,Ça ne changera plus..

Promise L'erreur de l'objet a“Bulles”Nature,Est passé en arrière tout le temps,Jusqu'à ce qu'il soit capturé.C'est - à - dire,Les erreurs sont toujours les suivantes catch Saisie des déclarations.

Nous savons tousthen Les méthodes produisent une nouvelle PromiseExemple,Si unPromise L'objet est suivi de plusieurs thenMéthodes,L'une ou l'autre de ces erreurs,Est le derniercatch()Capture.

  Points saillants:Alors...,Pas ici. then() Défini dans la méthode Reject Fonction de rappel de l'état(C'est - à - dire: then Deuxième paramètre pour),Le plus    Bien joué. catchMéthodes, Ceci capture l'avant thenErreur dans l'exécution de la méthode.

Promise.resolve()  

Parfois, vous devez convertir un objet existant en Promise Objet,Promise.resolve() C'est ce que font les méthodes..

let p = Promise.resolve('jack');
console.log(p);

Ouvrir la console, Regardez ce qui est sorti de ce code :

Il en résulte un PromiseObjet, Et l'état est réussi , La valeur du succès est le paramètre que nous avons passé 'jack' .

Promise.resolve() équivalent à l'écriture suivante:

Promise.resolve('jack')
// Équivalent à
new Promise(resolve => {resolve('jack')})

Promise.resolve()  Les paramètres de la méthode sont divisés en deux cas :

Le paramètre est unPromiseExemple:

Si le paramètre est Promise Exemple,AlorsPromise.resolve() Aucune modification ne sera apportée、Renvoie cette instance intacte.

let p1 = Promise.resolve('jack');
let p2 = Promise.resolve(p1);
console.log(p2);
//Promise {[[PromiseState]]: 'fulfilled', [[PromiseResult]]: 'jack'}

Le paramètre n'est pasPromise Objet ou aucun paramètre :

Promise.resolve() La méthode renvoie un nouveau Promise Objet,L'état est resolved

const p = Promise.resolve();

p.then(function () {
  // ...
});

Variables du code ci - dessus p Juste un. Promise Objet.

Il est important de noter que,Immédiatement. resolve() De Promise Objet,C'est dans ce tour.“Cycle des événements”(event loop)Exécuté à la fin de,Pas au prochain tour.“Cycle des événements”Au début de. 

setTimeout(function () {
  console.log('jack');
}, 0);

Promise.resolve().then(function () {
  console.log('andy');
});

console.log('david');

// david
// andy
// jack

Dans le code ci - dessus,setTimeout( fn , 0) Prochain tour“Cycle des événements”Exécution au début,Promise.resolve() Dans le cycle actuel“Cycle des événements”Exécution à la fin,console.log('david') Est exécuté immédiatement,Donc la première sortie.

Promise.reject()   

Promise.reject(reason) La méthode renvoie également un nouveau Promise Exemple,L'état de l'Instance est rejected .

let p1 = Promise.reject('Il y a eu une erreur');
console.log(p1);
//Promise { <rejected> 'Il y a eu une erreur' }
const p = Promise.reject('Il y a eu une erreur');
// équivalent à
const p = new Promise((resolve, reject) => reject('Il y a eu une erreur'))

p.then(null, function (s) {
  console.log(s)
});
// Une erreur s'est produite

Même si le paramètre que nous avons passé est un succès PromiseObjet, Il a aussi échoué :

let p1 = Promise.reject(new Promise((resolve, reject) => {
    resolve('ok');
}));
console.log(p1);
//Promise { <rejected> Promise { 'ok' } }

En ce momentPromiseObjetp1 L'état est un échec , Le résultat de son échec est la valeur que nous avons passée , C'est ce qui a réussi PromiseObjet,La compréhension simple est,Peu importe.,Promise.reject() L'état retourné doit être rejected 

Promise.all()    

Promise.all() Méthode utilisée pour utiliser plusieurs Promise Exemple,Emballé dans un nouveau Promise Exemple.

const p = Promise.all([p1, p2, p3]);
  • Promise.all() La méthode prend un tableau comme paramètre,
  • p1, p2, p3 Tous. Promise Exemple,Si ce n'est pas le cas,,Appelle d'abord.Promise.resolveMéthodes,Convertir le paramètre en Promise Exemple,Traitement ultérieur.
let p1 = Promise.resolve('jack');
let p2 = Promise.resolve(111);
const p3 = Promise.all([p1,p2,'andy']);
console.log(p3);

Ici, nous définissons deux états pour réussir PromiseObjet p1Etp2,Nous voulons passerPromise.all() La méthode fera plusieurs Promise Exemple,Emballé dans un nouveau Promise Exemple p3, Mais le dernier élément du tableau des paramètres n'est pas Promise L'objet est une chaîne ,Alors p3 Qu'est - ce qui va sortir?

Les résultats de sortie sont présentés dans la figure ci - dessus , Comme nous l'avons mentionné précédemment , S'il y a un élément dans le tableau qui n'est pas PromiseExemple,Sera appelé en premierPromise.resolveMéthodes,Convertir le paramètre en Promise Exemple,Encore une fois.

p L'état de p1, p2, p3 Décide que,Divisé en deux situations:

1. Seulement p1, p2, p3 Et l'état de fulfilled ,p L'état de fulfilled ,En ce moment p1, p2, p3 Les valeurs de retour de font un tableau,Passer àpFonction de rappel pour.

2. Tant que p1, p2, p3  L'un d'eux était rejected,p L'état de rejected ,Le premier est maintenant reject Valeur de retour de l'instance pour,Sera transmis àpFonction de rappel pour.

On va analyser un code :

const p1 = new Promise((resolve, reject) => {
  resolve('success');
}).then(value => value).catch(reason => reason);

const p2 = new Promise((resolve, reject) => {
  throw new Error('Mauvaise déclaration');
}).then(value => value).catch(reason => reason);

Promise.all([p1, p2]).then(value => {console.log(value)})
.catch(reason => {console.log(reason)});

Dans le code ci - dessus,p1Oui.resolved,p2D'abord.rejected,Maisp2J'en ai un.catchMéthodes,La méthode renvoie un nouveau Promise Exemple,p2En fait, c'est l'exemple.L'Instance est terminéecatchAprès la méthode,Et deviendraresolved,CausePromise.all() Les deux instances du paramètre de méthoderesolved,Donc il appellethenFonction de rappel spécifiée par la méthode,Sans appelercatchFonction de rappel spécifiée par la méthode.

Voici la sortie de ce code:

Sip2Il n'y en a pas.catchMéthodes,Appelle Promise.all() De catch Méthodes, C'est comme ça que ça se passe :

Promise.race()

Promise.race() De la même façon, plusieurs Promise Exemple,Emballé dans un nouveau Promise Exemple.

const p = Promise.race([p1, p2, p3]);

Dans le code ci - dessus,Tant quep1 , p2 , p3 L'un d'eux a été le premier à changer d'état,pEt l'état change.Celui qui a été le premier à changer Promise Valeur de retour de l'Instance,Passez - le àpFonction de rappel pour. 

Analysons ce que le code suivant devrait produire :

let p1 = new Promise((resolve,reject)=>{
  setTimeout(() => {
    resolve('ok');
  }, 1000);
})
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh year');
const result = Promise.race([p1,p2,p3]);
console.log(result);

Regardons d'abord.p1,p2,p3 Trois d'entre eux qui changent d'état en premier ,Sip1 Changez d'état. ,C'est... result Le résultat est que p1Décidé,Sip1 Le succès est si resultÇa marche., Le résultat de son succès est resultRésultats positifs. Mais parce que dans notre cas p1C'est un minuteur.,C'est une tâche asynchrone,Ce n'est certainement pas le cas.p1, En bas ,p1 Non, c'est sûr. p2 Changez d'état. , Nous regardons les résultats de la sortie sur la console :

Parce quep2L'état du succès,Alors...resultL'état defulfilled,Parce quep2Le résultat estsuccess,Alors...resultC'est la même chose.result.



Trois、PromisePrincipales questions 

1. Comment modifier l'état d'un objet

  1. resolve(value): Si c'est actuellement pending Et ça devient resolved
  2. reject(reason): Si c'est actuellement pending Et ça devient rejected
  3. Lancer une exception: Si c'est actuellement pending Et ça devient rejected( On peut lancer un ErrorObjet instance)

2.Possibilité d'effectuer plusieurs rappels

Quand promise Appelé lorsque l'état correspondant est changé

Regardons ce code:

let p = new Promise((resolve, reject) => {  resolve('OK');});

p.then(value => { console.log(value); });
p.then(value => { console.log(value+' again')});

Nous donnonsPromiseObjetp Deux rappels ont été faits , Est - ce que ça va marcher? ?Regardons la console:

La console imprime séquentiellement les sorties des deux callbacks ,Si et seulement siPromise Appelé seulement lorsque l'objet change à l'état correspondant .

Si dansPromise Interne non appelé resolve, Alors son état est pending, Donc on n'a pas changé d'état, donc thenLe rappel ne s'exécute pas non plus

Si vous changez ce code , Est - ce qu'il aura le même résultat? :

let p = new Promise((resolve, reject) => {  resolve('OK');});

p.then(value => {  console.log(value);}).then(value => { console.log(value+' again');});

Regardez d'abord les résultats de sortie :

Pourquoi dans le second rappel value- Oui.undefinedEt alors?? 

Parce que là - haut then Les détails de la méthode font référence à thenLa méthode renvoie un nouveauPromiseExemple(Attention!,Pas celui - là.PromiseExemple)

Sithen La fonction de rappel de la méthode a des données de retour , Alors ces données seront utilisées comme prochain thenParamètres de la fonction de rappel pour, Mais le premier de nos exemples ci - dessus thenNon.returnDonnées,Donc la deuxièmethen Je ne sais pas valueQui est - ce?, Si on était les premiers thenRiga.return value, De cette façon, le résultat sera le même que l'original .

3. Problème de séquence entre le changement d'état et l'exécution du rappel

C'est possible., Normalement, le rappel est spécifié avant le changement d'état, Mais vous pouvez aussi changer d'état avant de spécifier un rappel

QuandPromise La tâche dans l'exécuteur de l'objet est la tâche de synchronisation ,Appel directresolve, C'est une situation qui change d'abord PromiseÉtat de l'objet, Et ensuite aller spécifier le rappel

Voici un exemple de code:

let p = new Promise((resolve,reject) => {
     resolve('success');
});
p.then(value => {console.log(value);});

Quand est - ce quethenMéthode appliquée en premier,Et puisresolve Exécuter après le changement d'état ?

C'est quand une tâche asynchrone est dans une fonction d'actionneur , C'est - à - dire, Je dois attendre un moment pour changer d'état , Lorsque vous devez entrer dans la file d'attente asynchrone correspondante pour l'exécution ,Dans ce cas, c'estthenExécution en premier,resolve Exécution après changement d'état

Voici un exemple de code:

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('success');
    }, 1000);
});
p.then(value => {console.log(value);});

Résumons:

​ Spécifiez un rappel avant de changer d'état (Asynchrone):

  1. Spécifiez d'abord le rappel
  2. Encore un changement d'état
  3. Modifier l'état avant d'entrer dans la file d'attente asynchrone pour effectuer la fonction de rappel

Modifier l'état avant de spécifier le rappel (Synchroniser):

  1. Changement de statut
  2. Spécifier le rappel Et effectuer un rappel immédiatement

Alors comment changer l'état avant de spécifier le rappel ?

Attention!: La spécification n'est pas exécutée

  • Appelé directement dans l'actionneur resolve()/reject() , Ne pas utiliser de minuterie, etc. , Synchronisation directe dans l'actionneur
  • Délai plus long pour appeler then() ,In .then() Cette méthode est complétée par une couche supplémentaire, comme un timer

Quand aurons - nous les données ? 

  • Si le rappel spécifié en premier, Alors quand l'état change, La fonction de rappel appelle, Obtenir des données
  • Si vous changez d'état en premier, Alors, quand un rappel est spécifié, La fonction de rappel appelle, Obtenir des données

En termes simples,SiPromise L'objet a des tâches asynchrones dans son actionneur , Par exemple, si l'instruction de sortie est dans le minuteur , Spécifiez d'abord le rappel , Mais la désignation n'est pas exécutée . Il faut aussi attendre PromiseLorsque l'état de l'objet change, Pour revenir à la fonction de rappel .

4.then La méthode renvoie les résultats par quelle décision  

On l'a dit.,then La méthode renvoie un nouveau PromiseExemple ,Le nouveauPromise Qu'est - ce qui détermine l'état de l'objet , Quelles sont les caractéristiques de son retour des résultats ?

Expression simple:NouveauPromiseL'état de l'objet est défini parthen()La fonction de rappel spécifiée exécute la décision de résultat

Présentation détaillée:

1. Si une exception est lancée, Nouveau promise Devient rejected, reason Pour l'exception lancée

Exemple de code:

let p = new Promise((resolve,reject) => {
    resolve('success');
});
let result = p.then(value => {
     throw 'Il y a eu une erreur';
})
console.log(result);

Résultats obtenus:

2.Si oui ou non est retourné promise N'importe quelle valeur de, Nouveau promise Devient resolved, value Pour la valeur retournée

Exemple de code:

let p = new Promise((resolve,reject) => {
    resolve('success');
});
let result = p.then(value => {
    return 'jack';
})
console.log(result);

Résultats obtenus:

 

3.Si un autre nouveau promise, Ici. promise Le résultat sera nouveau promise Les résultats de

Exemple de code:

let p = new Promise((resolve,reject) => {
    resolve('success');
});
let result = p.then(value => {
    return new Promise((resolve,reject) => {
        reject('no');
    })
})
console.log(result);

Résultats obtenus:

5.Concaténation de plusieurs tâches

1. promise De then()Retour à un nouveau promise, Peut être considéré comme then()Appel en chaîne de

2. Adoption then Chaîne d'appels pour concaténer plusieurs synchronisations/Tâches asynchrones,Pour que ça marchethen() Concaténer plusieurs opérations synchrones ou asynchrones en une seule file d'attente synchrone

 Regardons d'abord ce code.:

let p = new Promise((resolve,reject) => {
     setTimeout(() => {
          resolve('ok');
     },1000)
});
p.then(value => {
     return new Promise((resolve,reject) => {
          resolve('success');
     })
}).then(value => {
     console.log(value);
})

Résultats obtenus:

Parce que le premierthenRetour à un nouveauPromiseObjet, Alors, ça. promise Le résultat sera nouveau promise Les résultats de,Donc à la finsuccess.

Ensuite, nous ajoutons un autre thenRappel:

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('ok');
    },1000)
});
p.then(value => {
    return new Promise((resolve,reject) => {
        resolve('success');
    })
}).then(value => {
    console.log(value);
}).then(value => {
    console.log(value);
})

Le dernier.value Quelle sera la sortie de ? La réponse est: undefined

Nous savons quethenLe résultat du retour dePromiseObjet,C'est ça.Promise L'état de l'objet est déterminé par la valeur de retour de la fonction de rappel qu'il spécifie ,Deuxièmethen La valeur de retour de la fonction de rappel pour est nulle ,C'estundefined,undefined Apparemment pas. PromiseObjet de type,Nous l'avons déjà dit.,Si oui ou non est retourné promise N'importe quelle valeur de, Nouveau promise Devient resolved, C'est - à - dire que l'état est réussi , Le résultat de son succès est le retour undefined.Parce que le secondthenRetour àPromise L'objet a réussi , Et le dernier then Premier rappel de , Et produit les résultats de son succès ,C'est - à - direundefined.C'est ça.thenAppel en chaîne de

6.Pénétration anormale

  • Lorsqu'il est utilisé promise De then Lors d'un appel en chaîne, Les rappels échoués peuvent être spécifiés à la fin
  • Il y a eu une exception à l'une des opérations précédentes, Est passé au dernier rappel qui a échoué

Exemple de code:

let p = new Promise((resolve,reject) => {
     setTimeout(() => {
          reject('Il y a eu une erreur');
     },1000)
});
p.then(value => {
     console.log(000);
}).then(value => {
     console.log(111);
}).then(value => {
     console.log(222);
}).catch(error => {
     console.warn(error);
})

Regardons d'abord les résultats. :

Il a produit le premier résultat Promise La valeur de son échec , On n'a pas besoin de s'occuper du milieu , Ne pas spécifier les callbacks échoués , Il suffit de spécifier un rappel échoué à la fin pour traiter les résultats échoués . Ce phénomène est une pénétration anormale .

Par exemple, nous avons lancé une erreur au milieu , Regarde le dernier catch Peut - on capturer  :

let p = new Promise((resolve,reject) => {
     setTimeout(() => {
          resolve('ok');
     },1000)
});
p.then(value => {
     throw 'Il y a eu une erreur';
}).then(value => {
     console.log(111);
}).then(value => {
     console.log(222);
}).catch(error => {
     console.warn(error);
})

Résultats obtenus:

Le premierthen L'erreur lancée dans le rappel est causée par le dernier catch Le rappel de la méthode pour traiter , C'est une pénétration anormale. .

7. Comment finir PromiseChaîne 

QuandpromiseLorsque l'état change, Ses appels enchaînés prendront effet , Donc si nous avons ce besoin réel :Nous avons4- Oui.then(), Mais il y a un jugement conditionnel , Si je suis ou non conforme à la clause 2- Oui.thenDans les conditions, Pour interrompre directement un appel en chaîne , Plus de marche en bas. then,Comment?

 Méthodes: Renvoie un pending Statut Promise Objet 

Exemple de code:

let p = new Promise((resolve,reject) => {
     setTimeout(() => {
          resolve('ok');
     },1000)
});
p.then(value => {
     console.log(111);
}).then(value => {
     console.log(222);
     return new Promise(()=>{})
}).then(value => {
     console.log(333);
}).then(value => {
     console.log(444);
})

Résultats obtenus:

Exemple d'analyse:

InterruptionPromise Il y a et il n'y a qu'une seule façon de , C'est - à - dire qu'il faut retourner à un pendingStatutPromiseObjet. Parce que si le retour est un succès PromiseObjet, Même si le résultat est undefinedMaisthen Le rappel à l'intérieur sera toujours exécuté ,SeulementpendingStatutPromiseLes objets sont différents, Parce que si un rappel renvoie pending,Alors, ça.then L'état retourné est également pendingDePromiseObjet,Si le premier(Dans cette question)thenRetour àpendingStatutPromiseObjet,Après ça.then Aucun rappel de la méthode ne peut être effectué ,Parce que l'état n'a pas changé, Impossible d'exécuter sans changer l'état .

  En termes simples: Changer l'état actuel en pending,Alors, à l'arrière.thenEtcatchNe pas exécuter  

  Ici, onPromise La première partie de ,On a apprisPromiseQuestions connexesAPI Et quelques questions clés , Mais c'est loin d'être suffisant pour un entretien d'embauche .Promise Dans la deuxième partie, nous allons essayer de personnaliser l'encapsulation Promise. Nous apprenons d'abord comment l'utiliser , Et apprendre à le réaliser à partir des principes .

J'espère voir ici les étudiants peuvent venir un bouton trois liens pour soutenir les étudiants !

版权声明
本文为[Xiaojie Learning Front End]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231811052703.html