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); });
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 ?
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; } } }
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); });
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');
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!