Maison  >  Article  >  interface Web  >  Implémenter la bibliothèque Promise en utilisant Js

Implémenter la bibliothèque Promise en utilisant Js

php中世界最好的语言
php中世界最好的语言original
2018-06-07 13:46:541902parcourir

Cette fois, je vais vous présenter l'utilisation de JS pour implémenter la bibliothèque Promise. Quelles sont les précautions à prendre pour utiliser JS pour implémenter la bibliothèque Promise ?

Préface

ECMAScript est la norme internationale pour le langage JavaScript, et JavaScript est l'implémentation d'ECMAScript. L'objectif d'ES6 est de permettre au langage JavaScript d'être utilisé pour écrire des applications volumineuses et complexes et de devenir un langage de développement au niveau de l'entreprise.

Concept

ES6 fournit nativement des objets Promise.

La soi-disant Promise est un objet utilisé pour transmettre des messages pour des opérations asynchrones. Il représente un événement (généralement une opération asynchrone) dont le résultat n'est connu que dans le futur, et cet événement fournit une API unifiée pour un traitement ultérieur.

Trois questions auxquelles réfléchir

Quand j'ai commencé à écrire le front-end, j'utilisais souvent le rappel pour gérer les requêtes asynchrones, ce qui est simple et pratique. Plus tard, comme je l'ai écrit, j'ai abandonné les rappels et j'ai commencé à utiliser des promesses pour résoudre les problèmes asynchrones. La promesse est en effet plus belle à écrire, mais en raison du manque de compréhension approfondie de sa structure interne, à chaque fois que l'on rencontre des situations complexes, il n'est toujours pas facile d'utiliser la promesse et le débogage prend beaucoup de temps.

Donc, dans cet article, je vais vous amener à repartir de zéro et à écrire à la main une promesse essentiellement utilisable. Après l'avoir écrite, vous aurez une compréhension claire de ce qu'est la promesse et de sa structure interne, et vous pourrez à l'avenir utiliser la promesse dans des scénarios complexes.

De plus, afin de tester si tout le monde maîtrise vraiment parfaitement les promesses, je donnerai quelques questions pratiques liées aux promesses à la fin de l'article. Bien qu'il s'agisse d'exercices, ce sont en réalité des abstractions de scénarios réels que vous rencontrerez dans vos projets. Les maîtriser avec compétence peut vous aider à améliorer vos compétences front-end.

Les trois questions pratiques sont données à l'avance. Vous pouvez ignorer le contenu ci-dessous et imaginer grossièrement comment vous allez les résoudre dans votre esprit :

  • appel en chaîne de tableau de promesses ?

  • Comment contrôler la concurrence avec les promesses ?

  • Comment faire une mise en cache asynchrone avec promesse ?

Les trois questions de réflexion ci-dessus n'ont en fait pas grand-chose à voir avec le fait que vous utilisiez ou non des promesses, mais si vous ne comprenez pas profondément les promesses, il n'est vraiment pas si facile de résoudre ces trois problèmes.

Qu'est-ce que la Promesse

Retour au texte, qu'est-ce que la Promesse ? Pour parler franchement, une promesse est un conteneur qui stocke le résultat d’un événement (généralement une opération asynchrone) qui se terminera dans le futur.

Tout d'abord, ES6 stipule que l'objet Promise est un constructeur utilisé pour générer des instances Promise. Ensuite, ce constructeur accepte une fonction (exécuteur) comme paramètre, et les deux paramètres de la fonction sont résoudre et rejeter. Enfin, une fois l'instance Promise générée, vous pouvez utiliser la méthode then pour spécifier les fonctions de rappel (onFulfilled et onRejected) pour l'état résolu et l'état rejeté respectivement.

La méthode d'utilisation spécifique est exprimée en code comme suit :

const promise = new Promise(function(resolve, reject) {
 // ... some code
 if (/* 异步操作成功 */){
 resolve(value);
 } else {
 reject(error);
 }
});
promise.then(function(value) {
 // success
}, function(error) {
 // failure
});

Après avoir compris cela, nous pouvons hardiment commencer à construire notre propre promesse, et nous lui donnons un nom : CutePromise

Implémenter une promesse : CutePromise

Nous utilisons directement les classes ES6 pour créer notre CutePromise Nous ne connaissons pas la syntaxe ES6, vous pouvez lire mon autre. deux articles présentant la syntaxe de base d'ES6 avant de revenir. Maîtrisez le contenu principal de ES6/ES2015 en 30 minutes (Partie 1), Maîtrisez le contenu principal de ES6/ES2015 en 30 minutes (Partie 2)

class CutePromise {
 // executor是我们实例化CutePromise时传入的参数函数,它接受两个参数,分别是resolve和reject。
 // resolve和reject我们将会定义在constructor当中,供executor在执行的时候调用
 constructor(executor) {
 const resolve = () => {}
 const reject = () => {}
 executor(resolve, reject)
 }
 // 为实例提供一个then的方法,接收两个参数函数,
 // 第一个参数函数必传,它会在promise已成功(fulfilled)以后被调用
 // 第二个参数非必传,它会在promise已失败(rejected)以后被调用
 then(onFulfilled, onRejected) {}
}

Après avoir créé notre CutePromise, trouvons une clé point : l'état de l'objet Promise.

L'objet Promise contrôle les opérations asynchrones via son propre état. Une instance Promise a trois états :

  • Opération asynchrone en attente (en attente)

  • Opération asynchrone réussie (réalisée)

  • L'opération asynchrone a échoué (rejetée)

Parmi les trois états ci-dessus, remplis et rejetés sont collectivement appelés résolus (finalisés). Il n'existe que deux chemins pour changer d'état : le premier depuis ending=>fulfilled et l'autre depuis ending=>rejected. Une fois le statut changé, il ne peut pas être modifié.

Ajoutons maintenant le statut à CutePromise. Le processus approximatif est :

首先,实例化初始过程中,我们先将状态设为PENDING,然后当executor执行resolve的时候,将状态更改为FULFILLED,当executor执行reject的时候将状态更改为REJECTED。同时更新实例的value。

constructor(executor) {
 ...
 this.state = 'PENDING';
 ...
 const resolve = (result) => {
  this.state = 'FULFILLED';
  this.value = result;
 }
 const reject = (error) => {
  this.state = 'REJECTED';
  this.value = error;
 }
 ...
}

再来看下我们的then函数。then函数的两个参数,onFulfilled表示当promise异步操作成功时调用的函数,onRejected表示当promise异步操作失败时调用的函数。假如我们调用then的时候,promise已经执行完成了(当任务是个同步任务时),我们可以直接根据实例的状态来执行相应的函数。假如promise的状态还是PENDING, 那我们就将onFulfilled和onRejected直接存储到chained这个变量当中,等promise执行完再调用。

constructor(executor) {
 ...
 this.state = 'PENDING';
 
 // chained用来储存promise执行完成以后,需要被依次调用的一系列函数
 this.chained = [];
 const resolve = (result) => {
  this.state = 'FULFILLED';
  this.value = result;
  
  // promise已经执行成功了,可以依次调用.then()函数里的onFulfilled函数了
  for (const { onFulfilled } of this.chained) {
   onFulfilled(res);
  }
 }
 ...
}
then(onFulfilled, onRejected) {
 if (this.state === 'FULFILLED') {
 onFulfilled(this.value);
 } else if (this.state === 'REJECTED') {
 onRejected(this.value);
 } else {
 this.$chained.push({ onFulfilled, onRejected });
 }
}

这样我们就完成了一个CutePromise的创建,下面是完整代码,大家可以复制代码到控制台测试一下:

class CutePromise {
 constructor(executor) {
 if (typeof executor !== 'function') {
  throw new Error('Executor must be a function');
 }
 this.state = 'PENDING';
 this.chained = [];
 const resolve = res => {
  if (this.state !== 'PENDING') {
  return;
  }
  this.state = 'FULFILLED';
  this.internalValue = res;
  for (const { onFulfilled } of this.chained) {
  onFulfilled(res);
  }
 };
 const reject = err => {
  if (this.state !== 'PENDING') {
  return;
  }
  this.state = 'REJECTED';
  this.internalValue = err;
  for (const { onRejected } of this.chained) {
  onRejected(err);
  }
 };
 try {
  executor(resolve, reject);
 } catch (err) {
  reject(err);
 }
 }
 
 then(onFulfilled, onRejected) {
 if (this.state === 'FULFILLED') {
  onFulfilled(this.internalValue);
 } else if (this.$state === 'REJECTED') {
  onRejected(this.internalValue);
 } else {
  this.chained.push({ onFulfilled, onRejected });
 }
 }
}

提供一下测试代码:

let p = new CutePromise(resolve => {
 setTimeout(() => resolve('Hello'), 100);
});
p.then(res => console.log(res));
p = new CutePromise((resolve, reject) => {
 setTimeout(() => reject(new Error('woops')), 100);
});
p.then(() => {}, err => console.log('Async error:', err.stack));
p = new CutePromise(() => { throw new Error('woops'); });
p.then(() => {}, err => console.log('Sync error:', err.stack));

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

JS实现输入框内灰色文字提示

路径中#号怎样除去

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!

Déclaration:
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