Maison  >  Article  >  interface Web  >  Une discussion détaillée sur la programmation asynchrone nodejs_node.js

Une discussion détaillée sur la programmation asynchrone nodejs_node.js

WBOY
WBOYoriginal
2016-05-16 16:29:191456parcourir

Les exigences actuelles impliquent un grand nombre d'opérations asynchrones, et les pages réelles penchent de plus en plus vers des applications monopage. À l'avenir, vous pourrez utiliser des frameworks backbone, angulaire, knock-out et autres, mais le problème de la programmation asynchrone est le premier problème auquel il faut faire face. Avec l’essor des nœuds, la programmation asynchrone est devenue un sujet très brûlant. Après une période d'étude et de pratique, quelques détails de la programmation asynchrone sont résumés.

1.Classification de la programmation asynchrone

Les méthodes pour résoudre les problèmes asynchrones incluent généralement : le rappel direct, le mode pub/sub (mode événement), la bibliothèque de contrôle de bibliothèque asynchrone (telle que async, when), la promesse, le générateur, etc.
1.1 Fonction de rappel

La fonction de rappel est une méthode couramment utilisée pour résoudre des problèmes asynchrones. Elle est souvent contactée et utilisée, facile à comprendre et très facile à implémenter dans des bibliothèques ou des fonctions. C'est également une méthode souvent utilisée par tout le monde lors de l'utilisation de la programmation asynchrone.

Mais la méthode de la fonction de rappel présente les problèmes suivants :

1. Il peut former une pyramide imbriquée maléfique et le code est difficile à lire

2. Ne peut correspondre qu'à une seule fonction de rappel, ce qui devient une limitation dans de nombreux scénarios.

Mode pub/sub 1.2 (événement)

Ce mode est également appelé mode événement, qui est l'événementisation des fonctions de rappel. Il est très courant dans les bibliothèques telles que jQuery.

Le modèle d'abonné de publication d'événements lui-même n'a pas de problème d'appels synchrones et asynchrones, mais dans le nœud, les appels d'émission sont principalement déclenchés de manière asynchrone avec la boucle d'événements. Ce mode est souvent utilisé pour découpler la logique métier. L'éditeur d'événements n'a pas besoin de prêter attention aux fonctions de rappel enregistrées, ni au nombre de fonctions de rappel qui peuvent être transférées de manière flexible via les messages.

Les avantages de ce mode sont : 1. Facile à comprendre ; 2. Ne se limite plus à une seule fonction de rappel.

Inconvénients : 1. Nécessité d'utiliser une bibliothèque de classes ; 2. L'ordre des événements et des fonctions de rappel est très important

Copier le code Le code est le suivant :

var img = document.querySelect(#id);
img.addEventListener('load', function() {
// Chargement de l'image terminé
 …
});
img.addEventListener('erreur', function() {
// Quelque chose s'est mal passé
……
});

Il y a deux problèmes avec le code ci-dessus :

a. L'img a effectivement été chargé et la fonction de rappel de chargement n'est liée qu'à ce moment-là. Par conséquent, le rappel ne sera pas exécuté, mais nous espérons toujours exécuter la fonction de rappel correspondante.

Copier le code Le code est le suivant :

var img = document.querySelect(#id);
fonction charger() {
...
>
si (img.complete) {
charger();
} autre {
img.addEventListener('load', load);
>
img.addEventListener('erreur', function() {
// Quelque chose s'est mal passé
……
});

b. Incapable de bien gérer les exceptions

Conclusion : le mécanisme d'événement est le plus approprié pour gérer des événements qui se produisent de manière répétée sur le même objet. Il n'est pas nécessaire de prendre en compte l'occurrence d'événements avant que la fonction de rappel ne soit liée.

1.3 Bibliothèque de contrôle asynchrone

Les bibliothèques asynchrones actuelles incluent principalement Q, when.js, win.js, RSVP.js, etc.

La caractéristique de ces bibliothèques est que le code est linéaire et peut être écrit de haut en bas, ce qui est conforme aux habitudes naturelles.

L'inconvénient est que les styles sont différents, ce qui rend la lecture difficile et augmente le coût de l'apprentissage.

Promesse 1.4

La promesse est traduite en chinois par promesse. Ma compréhension personnelle est qu'après l'achèvement asynchrone, elle donnera un résultat externe (succès ou échec) et promet que le résultat ne changera pas. En d'autres termes, la promesse reflète la valeur de retour éventuelle d'une opération (une promesse représente la valeur éventuelle renvoyée par l'achèvement unique d'une opération). À l'heure actuelle, Promise a été introduit dans la spécification ES6 et les navigateurs avancés tels que Chrome et Firefox ont implémenté cette méthode native en interne, ce qui est très pratique à utiliser.

Analysons les caractéristiques de Promise sous les aspects suivants :

1.4.1 Statut

Contient trois états : en attente, réalisé et rejeté. Seules deux transitions peuvent se produire entre les trois états (de en attente--->réalisé, en attente-->rejeté), et la transition d'état ne peut se produire qu'une seule fois.

1.4.2 puis méthode

La méthode then est utilisée pour spécifier la fonction de rappel une fois l'événement asynchrone terminé.

Cette méthode peut être considérée comme la méthode de l'âme de Promise, qui rend Promise pleine de magie. Il existe plusieurs manifestations spécifiques comme suit :

a) La méthode then renvoie Promise. Cela permet des opérations en série de plusieurs opérations asynchrones.

Concernant le traitement de la valeur dans le cercle jaune 1 dans l'image ci-dessus, il s'agit d'une partie plus compliquée de Promise. Le traitement de la valeur est divisé en deux situations : l'objet Promise et l'objet non-Promise.

Lorsque la valeur n'est pas de type Promise, utilisez simplement value comme valeur de paramètre de la résolution de la deuxième Promise ; lorsqu'elle est de type Promise, le statut et les paramètres de promise2 sont entièrement déterminés par la valeur. promsie2 est complètement une marionnette de valeur, promise2 n'est qu'un pont reliant différents asynchrones.

Copier le code Le code est le suivant :

Promise.prototype.then = function (onFulfilled, onRejected) {
    return new Promise(function(resolve, rejet) {           //此处的Promise标注为promise2
        gérer({
            onFulfilled : onFulfilled,
            onRejected : onRejected,
            résoudre : résoudre,
            rejeter : rejeter
        })
    });
>
handle de fonction (différé) {
    var handleFn;
    if(state === 'rempli') {
        handleFn = différé.onFulfilled;
    } else if(state === 'rejeté') {
        handleFn = différé.onRejected;
    >
    var ret = handleFn(valeur);
    différé.resolve(ret);                           //注意,此时的resolve是promise2的resolve
>
fonction ressolve(val) {
    if(val && typeof val.then === 'function') {
        val.then(resolve);                           // if val为promise对象或类promise对象时,promise2的状态完全由val决定
        revenir ;
    >
    if(callback) {                                    // rappel为指定的回调函数
        rappel(val);
    >
>

  b)实现了多个不同异步库之间的转换。

    在异步中存在一个叫thenable的对象,就是指具有then方法的对象,只要一个对象对象具有then方法,就可以对其进行转换,例如:

复制代码 代码如下 :

var différé = $('aa.ajax');      // !!deferred.then  === true
var P = Promise.resolve (différé);
p.puis(......)

1.4.3 commonJS Promise/A规范

      目前关于Promise的规范存在Promise/A和Promise/A 规范,这说明关于Promise的实现是挺复杂的。

复制代码 代码如下 :

puis (fulfilledHandler, rejetéHandler, progressHandler)

1.4.4 注意事项

     La promesse est une valeur sûre果value是对象,那就要小心不要轻易修改value的值。

复制代码 代码如下 :

var p = Promise.resolve({x: 1});
p.then(fonction(val) {
    console.log('premier rappel : ' val.x );
});
p.then(function(val) {
    console.log('deuxième rappel : 'val.x)
})
// premier rappel : 1
// deuxième rappel : 2

Générateur 1.5

Toutes les méthodes ci-dessus sont basées sur des fonctions de rappel pour effectuer des opérations asynchrones. Elles ne sont rien de plus qu'une encapsulation de fonctions de rappel. Generator est proposé dans ES6, ce qui ajoute un moyen de résoudre les opérations asynchrones et ne repose plus sur des fonctions de rappel.

La plus grande fonctionnalité de Generator est qu'il peut mettre en pause et redémarrer des fonctions. Cette fonctionnalité est très utile pour résoudre les opérations asynchrones. La combinaison de la pause du générateur avec la gestion des exceptions de la promesse peut résoudre les problèmes de programmation asynchrone de manière plus élégante. Référence d'implémentation spécifique : Kyle Simpson

2. Problèmes de programmation asynchrone

2.1 Gestion des exceptions

a) Les événements asynchrones comprennent deux liens : l'émission de requêtes asynchrones et le traitement des résultats. Ces deux liens sont connectés via une boucle d'événements. Ensuite, lorsque try catch est utilisé pour capturer des exceptions, il doit être capturé séparément.

Copier le code Le code est le suivant :

essayez {
asyncEvent(rappel);
} attraper (erreur) {
 …
>

Le code ci-dessus ne peut pas capturer l'exception dans le rappel, mais ne peut obtenir l'exception que dans le processus de demande. Cela crée un problème : si l'émission de la demande et le traitement de la demande sont effectués par deux personnes, y aura-t-il un problème lors du traitement des exceptions ?

b) Promise implémente la livraison d'exceptions, ce qui apporte certains avantages et garantit que le code n'est pas bloqué dans les projets réels. Mais s’il existe de nombreux événements asynchrones, il n’est pas facile de savoir quel événement asynchrone a provoqué l’exception.

Copier le code Le code est le suivant :

// Description du scénario : Afficher les informations d'alarme de prix dans CRM, y compris les informations sur la concurrence. Cependant, l'obtention des informations sur la compétition prend beaucoup de temps. Afin d'éviter des requêtes lentes, le backend a divisé un enregistrement en deux morceaux et les a obtenus séparément.
// Première étape : Obtenez des informations sur les alarmes de prix, en plus des informations sur la concurrence
fonction getPriceAlarmData() {
Renvoie une nouvelle promesse (fonction (résolution) {
Y.io(url, {
Méthode : 'obtenir',
               données : paramètres,
sur : fonction() {
Succès : fonction (id, données) {
résoudre (données d'alarme);
                }
            }
        });
});
>
// Après avoir obtenu les informations d'alarme, obtenez les informations sur la compétition
getPriceAlarmData().then(function(data) {
//Rendu des données, sauf informations sur la compétition
rendre(données);
Renvoie une nouvelle promesse (fonction (résolution) {
Y.io(url, {
Méthode : 'obtenir',
              données : {alarmList : data},
sur : fonction() {
Succès : function(id, compData) {
                        solve(compData);
                }
            }
        });
});
}) // Après avoir obtenu toutes les données, restituez les informations du concours
.then(fonction(données) {
// Rendu des informations sur le concours
rendu (données)
}, fonction (erreur) {
//Gestion des exceptions
console.log(err);
});

Vous pouvez convertir le code ci-dessus en ce qui suit :

Copier le code Le code est le suivant :

essayez{
// Récupérer les informations d'alarme autres que la compétition
var alarmData = alarmDataExceptCompare();
render(alarmData);
// Interroger les informations sur la compétition en fonction des informations d'alarme
var compareData = getCompareInfo(alarmData);
render(compareData);
} attraper (erreur) {
console.log(err.message);
>

Dans l'exemple ci-dessus, la gestion des exceptions est placée à la fin, de sorte que lorsqu'une exception se produit dans un certain lien, nous ne pouvons pas savoir avec précision quel événement l'a provoquée.       

2.2 Problèmes avec jQuery.Deferred

Les opérations asynchrones sont également implémentées dans jQuery, mais l'implémentation n'est pas conforme à la spécification promise/A, principalement dans les aspects suivants :

a. Nombre de paramètres : Standard Promise ne peut accepter qu'un seul paramètre, tandis que jQuery peut transmettre plusieurs paramètres

Copier le code Le code est le suivant :

fonction asyncInJQuery() {
var d = nouveau $.Deferred();
setTimeout(fonction() {
         d.resolve(1, 2);
}, 100);
Retourner d.promise()
>
asyncInJQuery().then(function(val1, val2) {
console.log('output: ', val1, val2);
});
// sortie : 1 2

b. Gestion des exceptions dans le traitement des résultats

Copier le code Le code est le suivant :

fonction asyncInPromise() {
Renvoie une nouvelle promesse (fonction (résolution) {
​​​​ setTimeout(function() {
          var jsonStr = '{"name": "mt}';
            solve(jsonStr);
}, 100);
});
>
asyncInPromise().then(function(val) {
var d = JSON.parse(val);
console.log(d.name);
}).then(null, function(err) {
console.log('show error: ' err.message);
});
// affiche l'erreur : fin inattendue de la saisie
fonction asyncInJQuery() {
var d = nouveau $.Deferred();
setTimeout(fonction() {
        var jsonStr = '{"name": "mt}';
         d.resolve(jsonStr);
}, 100);
Retourner d.promise()
>
asyncInJQuery().then(function(val) {
var d = JSON.parse(val);
console.log(d.name);
}).then(function(v) {
console.log('success: ', v.name);
}, fonction(erreur){
console.log('show error: ' err.message);
});
//Uncaught SyntaxError : fin inattendue de la saisie

On peut voir à partir de cela que Promise effectue le traitement des résultats sur la fonction de rappel et peut capturer les exceptions lors de l'exécution de la fonction de rappel, mais jQuery.Deferred ne le peut pas.

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