


Interprétation détaillée de l'utilisation de Promise dans la programmation JavaScript_Connaissances de base
Description principale de la promesse
Bien que Promise ait déjà ses propres spécifications, les différentes bibliothèques Promise actuelles présentent des différences dans les détails d'implémentation de Promise, et certaines API ont même une signification complètement différente. Mais le contenu principal de Promise est le même, c'est la méthode then. En termes connexes, une promesse fait référence à un objet ou une fonction doté d'une méthode then pouvant déclencher un comportement spécifique.
La promesse peut être implémentée de différentes manières, de sorte que la description principale de la promesse ne traite d'aucun code d'implémentation spécifique.
Lisez d'abord la description principale de Promise. Cela signifie : Regardez, c'est le résultat qui doit être écrit. Veuillez vous référer à ce résultat pour réfléchir à la façon de l'écrire dans le code.
Pour commencer : comprenez la promesse de cette manière
Rappelez-vous quel problème Promise résout ? rappel. Par exemple, la fonction doMission1() représente la première chose. Maintenant, nous voulons faire la prochaine chose doMission2() une fois cette chose terminée. Que devons-nous faire ?
Jetons d’abord un coup d’œil à nos modèles de rappel courants. doMission1() a dit : "Si vous voulez faire cela, donnez-moi doMission2() et je l'appellerai pour vous une fois terminé." Ce sera donc :
doMission1(doMission2);
Qu'en est-il du mode Promesse ? Vous avez dit à doMission1() : "Non, le contrôle est avec moi. Vous devriez le changer. Vous me rendez d'abord une chose spéciale, puis j'utiliserai cette chose pour organiser la chose suivante." cela ressemblera à ceci :
doMission1().then(doMission2);
On peut voir que Promise change la relation maître-esclave du mode de rappel (retournez-vous et devenez le maître !). La relation de processus de plusieurs événements peut être concentrée sur la route principale (au lieu d'être dispersée entre divers événements). fonctions).
Bon, comment faire une telle conversion ? Commençons par le cas le plus simple, en supposant que le code de doMission1() est :
function doMission1(callback){ var value = 1; callback(value); }
Ensuite, il peut être modifié pour ressembler à ceci :
function doMission1(){ return { then: function(callback){ var value = 1; callback(value); } }; }
Ceci termine la conversion. Bien qu'il ne s'agisse pas d'une conversion réellement utile, nous avons ici abordé le point d'implémentation le plus important de Promise, c'est-à-dire que Promise convertit la valeur de retour en un objet avec une méthode then.
Avancé : le parcours de conception de Q
Commencer à partir du report
design/q0.js est la première étape de la mise en forme initiale de Q. Il crée une fonction utilitaire appelée defer pour créer Promise :
var defer = function () { var pending = [], value; return { resolve: function (_value) { value = _value; for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; callback(value); } pending = undefined; }, then: function (callback) { if (pending) { pending.push(callback); } else { callback(value); } } } };
Comme le montre ce code source, exécuter defer() obtiendra un objet qui contient deux méthodes : résoudre puis. Veuillez rappeler Deferred de jQuery (également résoudre et ensuite), ces deux méthodes auront des effets similaires. Ensuite, il fera référence à l'état en attente, et s'il est en attente, le rappel sera enregistré (push), sinon le rappel sera appelé immédiatement. solve confirmera la promesse, mettra à jour la valeur et exécutera tous les rappels enregistrés en même temps. Des exemples d'utilisation différée sont les suivants :
var oneOneSecondLater = function () { var result = defer(); setTimeout(function () { result.resolve(1); }, 1000); return result; };
oneOneSecondLater().then(callback);
Ici, oneOneSecondLater() contient du contenu asynchrone (setTimeout), mais ici il renvoie immédiatement un objet généré par defer(), puis appelle la méthode de résolution de l'objet à la fin de la fin asynchrone (avec la valeur supérieure, ou dans un autre résultat des mots).
À ce stade, il y a un problème avec le code ci-dessus : la résolution peut être exécutée plusieurs fois. Par conséquent, le jugement du statut doit être ajouté à la résolution pour garantir que la résolution n'est valable qu'une seule fois. Voici la prochaine étape design/q1.js de Q (uniquement la partie différence) :
resolve: function (_value) { if (pending) { value = _value; for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; callback(value); } pending = undefined; } else { throw new Error("A promise can only be resolved once."); } }
Pour le deuxième appel et les suivants, vous pouvez générer une erreur comme celle-ci, ou vous pouvez simplement l'ignorer.
Séparer le report et la promesse
Dans l'implémentation précédente, l'objet généré par defer a à la fois la méthode then et la méthode solve. Par définition, la promesse se soucie de la méthode then. Quant à la détermination qui déclenche la promesse de changer d’état, c’est une autre affaire. Par conséquent, Q séparera ensuite la promesse avec la méthode then et le defer avec la résolution, et les utilisera indépendamment. Cela revient à clarifier leurs responsabilités respectives et à ne laisser que certaines autorisations. Cela rendra la logique du code plus claire et plus facile à ajuster. Veuillez consulter design/q3.js : (q2 est ignoré ici)
var isPromise = function (value) { return value && typeof value.then === "function"; }; var defer = function () { var pending = [], value; return { resolve: function (_value) { if (pending) { value = _value; for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; callback(value); } pending = undefined; } }, promise: { then: function (callback) { if (pending) { pending.push(callback); } else { callback(value); } } } }; };
Si vous comparez attentivement le q1, vous constaterez que la différence est très faible. D'une part, l'erreur n'est plus générée (au lieu d'ignorer directement la seconde résolution et d'autres), d'autre part, la méthode then est déplacée vers un objet nommé promise. À ce stade, l'objet obtenu en exécutant defer() (appelons-le defer) aura une méthode de résolution et un attribut de promesse pointant vers un autre objet. Cet autre objet est une promesse avec seulement une méthode then. Ceci complète la séparation.
Il y a aussi une fonction isPromise() devant, qui détermine si l'objet est une promesse selon s'il a une méthode then (méthode de jugement par typage canard). Afin d'utiliser et de gérer correctement les promesses détachées, vous devez distinguer les promesses des autres valeurs comme celle-ci.
Mise en œuvre de la cascade de promesses
La prochaine étape sera assez importante. Jusqu’au troisième trimestre, les promesses mises en œuvre ne peuvent pas être répercutées. Mais les promesses que vous connaissez devraient prendre en charge une syntaxe comme celle-ci :
promise.then(step1).then(step2);
以上过程可以理解为,promise将可以创造新的promise,且取自旧的promise的值(前面代码中的value)。要实现then的级联,需要做到一些事情:
- then方法必须返回promise。
- 这个返回的promise必须用传递给then方法的回调运行后的返回结果,来设置自己的值。
- 传递给then方法的回调,必须返回一个promise或值。
design/q4.js中,为了实现这一点,新增了一个工具函数ref:
var ref = function (value) { if (value && typeof value.then === "function") return value; return { then: function (callback) { return ref(callback(value)); } }; };
这是在着手处理与promise关联的value。这个工具函数将对任一个value值做一次包装,如果是一个promise,则什么也不做,如果不是promise,则将它包装成一个promise。注意这里有一个递归,它确保包装成的promise可以使用then方法级联。为了帮助理解它,下面是一个使用的例子:
ref("step1").then(function(value){ console.log(value); // "step1" return 15; }).then(function(value){ console.log(value); // 15 });
你可以看到value是怎样传递的,promise级联需要做到的也是如此。
design/q4.js通过结合使用这个ref函数,将原来的defer转变为可级联的形式:
var defer = function () { var pending = [], value; return { resolve: function (_value) { if (pending) { value = ref(_value); // values wrapped in a promise for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; value.then(callback); // then called instead } pending = undefined; } }, promise: { then: function (_callback) { var result = defer(); // callback is wrapped so that its return // value is captured and used to resolve the promise // that "then" returns var callback = function (value) { result.resolve(_callback(value)); }; if (pending) { pending.push(callback); } else { value.then(callback); } return result.promise; } } }; };
原来callback(value)的形式,都修改为value.then(callback)。这个修改后效果其实和原来相同,只是因为value变成了promise包装的类型,会需要这样调用。
then方法有了较多变动,会先新生成一个defer,并在结尾处返回这个defer的promise。请注意,callback不再是直接取用传递给then的那个,而是在此基础之上增加一层,并把新生成的defer的resolve方法放置在此。此处可以理解为,then方法将返回一个新生成的promise,因此需要把promise的resolve也预留好,在旧的promise的resolve运行后,新的promise的resolve也会随之运行。这样才能像管道一样,让事件按照then连接的内容,一层一层传递下去。
加入错误处理
promise的then方法应该可以包含两个参数,分别是肯定和否定状态的处理函数(onFulfilled与onRejected)。前面我们实现的promise还只能转变为肯定状态,所以,接下来应该加入否定状态部分。
请注意,promise的then方法的两个参数,都是可选参数。design/q6.js(q5也跳过)加入了工具函数reject来帮助实现promise的否定状态:
var reject = function (reason) { return { then: function (callback, errback) { return ref(errback(reason)); } }; };
它和ref的主要区别是,它返回的对象的then方法,只会取第二个参数的errback来运行。design/q6.js的其余部分是:
var defer = function () { var pending = [], value; return { resolve: function (_value) { if (pending) { value = ref(_value); for (var i = 0, ii = pending.length; i < ii; i++) { value.then.apply(value, pending[i]); } pending = undefined; } }, promise: { then: function (_callback, _errback) { var result = defer(); // provide default callbacks and errbacks _callback = _callback || function (value) { // by default, forward fulfillment return value; }; _errback = _errback || function (reason) { // by default, forward rejection return reject(reason); }; var callback = function (value) { result.resolve(_callback(value)); }; var errback = function (reason) { result.resolve(_errback(reason)); }; if (pending) { pending.push([callback, errback]); } else { value.then(callback, errback); } return result.promise; } } }; };
这里的主要改动是,将数组pending只保存单个回调的形式,改为同时保存肯定和否定的两种回调的形式。而且,在then中定义了默认的肯定和否定回调,使得then方法满足了promise的2个可选参数的要求。
你也许注意到defer中还是只有一个resolve方法,而没有类似jQuery的reject。那么,错误处理要如何触发呢?请看这个例子:
var defer1 = defer(), promise1 = defer1.promise; promise1.then(function(value){ console.log("1: value = ", value); return reject("error happens"); }).then(function(value){ console.log("2: value = ", value); }).then(null, function(reason){ console.log("3: reason = ", reason); }); defer1.resolve(10); // Result: // 1: value = 10 // 3: reason = error happens
可以看出,每一个传递给then方法的返回值是很重要的,它将决定下一个then方法的调用结果。而如果像上面这样返回工具函数reject生成的对象,就会触发错误处理。
融入异步
终于到了最后的design/q7.js。直到前面的q6,还存在一个问题,就是then方法运行的时候,可能是同步的,也可能是异步的,这取决于传递给then的函数(例如直接返回一个值,就是同步,返回一个其他的promise,就可以是异步)。这种不确定性可能带来潜在的问题。因此,Q的后面这一步,是确保将所有then转变为异步。
design/q7.js定义了另一个工具函数enqueue:
var enqueue = function (callback) { //process.nextTick(callback); // NodeJS setTimeout(callback, 1); // Na?ve browser solution };
显然,这个工具函数会将任意函数推迟到下一个事件队列运行。
design/q7.js其他的修改点是(只显示修改部分):
var ref = function (value) { // ... return { then: function (callback) { var result = defer(); // XXX enqueue(function () { result.resolve(callback(value)); }); return result.promise; } }; }; var reject = function (reason) { return { then: function (callback, errback) { var result = defer(); // XXX enqueue(function () { result.resolve(errback(reason)); }); return result.promise; } }; }; var defer = function () { var pending = [], value; return { resolve: function (_value) { // ... enqueue(function () { value.then.apply(value, pending[i]); }); // ... }, promise: { then: function (_callback, _errback) { // ... enqueue(function () { value.then(callback, errback); }); // ... } } }; };
即把原来的value.then的部分,都转变为异步。
到此,Q提供的Promise设计原理q0~q7,全部结束。
结语
即便本文已经是这么长的篇幅,但所讲述的也只到基础的Promise。大部分Promise库会有更多的API来应对更多和Promise有关的需求,例如all()、spread(),不过,读到这里,你已经了解了实现Promise的核心理念,这一定对你今后应用Promise有所帮助。
在我看来,Promise是精巧的设计,我花了相当一些时间才差不多理解它。Q作为一个典型Promise库,在思路上走得很明确。可以感受到,再复杂的库也是先从基本的要点开始的,如果我们自己要做类似的事,也应该保持这样的心态一点一点进步。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de reconnaissance vocale en ligne Introduction : Avec le développement continu de la technologie, la technologie de reconnaissance vocale est devenue une partie importante du domaine de l'intelligence artificielle. Le système de reconnaissance vocale en ligne basé sur WebSocket et JavaScript présente les caractéristiques d'une faible latence, d'un temps réel et d'une multiplateforme, et est devenu une solution largement utilisée. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de reconnaissance vocale en ligne.

WebSocket et JavaScript : technologies clés pour réaliser des systèmes de surveillance en temps réel Introduction : Avec le développement rapide de la technologie Internet, les systèmes de surveillance en temps réel ont été largement utilisés dans divers domaines. L'une des technologies clés pour réaliser une surveillance en temps réel est la combinaison de WebSocket et de JavaScript. Cet article présentera l'application de WebSocket et JavaScript dans les systèmes de surveillance en temps réel, donnera des exemples de code et expliquera leurs principes de mise en œuvre en détail. 1. Technologie WebSocket

Introduction à l'utilisation de JavaScript et de WebSocket pour mettre en œuvre un système de commande en ligne en temps réel : avec la popularité d'Internet et les progrès de la technologie, de plus en plus de restaurants ont commencé à proposer des services de commande en ligne. Afin de mettre en œuvre un système de commande en ligne en temps réel, nous pouvons utiliser les technologies JavaScript et WebSocket. WebSocket est un protocole de communication full-duplex basé sur le protocole TCP, qui peut réaliser une communication bidirectionnelle en temps réel entre le client et le serveur. Dans le système de commande en ligne en temps réel, lorsque l'utilisateur sélectionne des plats et passe une commande

Dans la vie quotidienne, nous rencontrons souvent des problèmes entre promesses et réalisation. Que ce soit dans une relation personnelle ou dans une transaction commerciale, tenir ses promesses est essentiel pour instaurer la confiance. Cependant, les avantages et les inconvénients de l’engagement sont souvent controversés. Cet article explorera les avantages et les inconvénients des engagements et donnera quelques conseils sur la façon de tenir parole. Les avantages promis sont évidents. Premièrement, l’engagement renforce la confiance. Lorsqu’une personne tient parole, elle fait croire aux autres qu’elle est une personne digne de confiance. La confiance est le lien établi entre les personnes, qui peut les rendre plus

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de réservation en ligne. À l'ère numérique d'aujourd'hui, de plus en plus d'entreprises et de services doivent fournir des fonctions de réservation en ligne. Il est crucial de mettre en place un système de réservation en ligne efficace et en temps réel. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de réservation en ligne et fournit des exemples de code spécifiques. 1. Qu'est-ce que WebSocket ? WebSocket est une méthode full-duplex sur une seule connexion TCP.

JavaScript et WebSocket : Construire un système efficace de prévisions météorologiques en temps réel Introduction : Aujourd'hui, la précision des prévisions météorologiques revêt une grande importance pour la vie quotidienne et la prise de décision. À mesure que la technologie évolue, nous pouvons fournir des prévisions météorologiques plus précises et plus fiables en obtenant des données météorologiques en temps réel. Dans cet article, nous apprendrons comment utiliser la technologie JavaScript et WebSocket pour créer un système efficace de prévisions météorologiques en temps réel. Cet article démontrera le processus de mise en œuvre à travers des exemples de code spécifiques. Nous

Tutoriel JavaScript : Comment obtenir le code d'état HTTP, des exemples de code spécifiques sont requis Préface : Dans le développement Web, l'interaction des données avec le serveur est souvent impliquée. Lors de la communication avec le serveur, nous devons souvent obtenir le code d'état HTTP renvoyé pour déterminer si l'opération a réussi et effectuer le traitement correspondant en fonction de différents codes d'état. Cet article vous apprendra comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournira quelques exemples de codes pratiques. Utilisation de XMLHttpRequest

Une explication détaillée de Promise.resolve() nécessite des exemples de code spécifiques. Promise est un mécanisme en JavaScript pour gérer les opérations asynchrones. Dans le développement réel, il est souvent nécessaire de traiter certaines tâches asynchrones qui doivent être exécutées dans l'ordre, et la méthode Promise.resolve() est utilisée pour renvoyer un objet Promise qui a été rempli. Promise.resolve() est une méthode statique de la classe Promise, qui accepte un
