Préface
Le plus grand point culminant de NodeJS est le modèle d'E / S non bloquant les événements, qui fait que NodeJS a de solides capacités de traitement de la concurrence et est très adapté à la rédaction d'applications réseau. La plupart des opérations d'E / S dans NodeJS sont presque asynchrones, c'est-à-dire que les résultats de nos opérations d'E / S doivent essentiellement être traités dans la fonction de rappel, comme la fonction suivante qui lit le contenu du fichier:
La copie de code est la suivante:
fs.readfile ('/ etc / passwd', fonction (err, data) {
si (err) jetez ERR;
console.log (données);
});
Alors, que devons-nous faire si nous lisons deux fichiers et fusionnons le contenu de ces deux fichiers ensemble? La plupart des personnes qui ne sont pas en contact avec JS peuvent le faire:
La copie de code est la suivante:
fs.readfile ('/ etc / passwd', fonction (err, data) {
si (err) jetez ERR;
fs.readfile ('/ etc / passwd2', fonction (err, data2) {
si (err) jetez ERR;
// Traitez les données des données et des données2 ici
});
});
Si vous traitez plusieurs scénarios similaires, ne serait-il pas que les fonctions de rappel soient imbriquées par couche? C'est ce que les gens rappellent souvent la pyramide ou l'enfer de rappel (http://callbackhell.com/), et c'est aussi le problème le plus gênant pour JS Novice.
Ce type de code imbriqué a apporté de nombreux problèmes au développement, principalement reflété dans:
1. La possibilité de code s'aggrave
2. Difficultés de débogage
3. Il est difficile de vérifier après une exception
Cet article présente principalement comment gérer élégamment les problèmes de rappel asynchrones ci-dessus.
Solution principale: traitez récursivement les rappels asynchrones
Nous pouvons utiliser Recursion comme outil de contrôle d'exécution pour le code. Encapsuler les opérations qui doivent être exécutées dans une fonction et contrôler le processus d'exécution du code en appelant récursivement dans la fonction de rappel. Sans plus tarder, parlons de non-sens, jetons un coup d'œil au code précédent:
La copie de code est la suivante:
var fs = require ('fs');
// Liste des fichiers à traiter
var files = ['file1', 'file2', 'file3'];
fonction parsefile () {
if (files.length == 0) {
retour;
}
var file = files.shift ();
fs.readfile (fichier, fonction (err, data) {
// traite les données des fichiers ici
parsefile (); // Après le traitement, traitez le fichier suivant via un appel récursif
});
}
// commence à traiter
parsefile ();
Le code ci-dessus a traité les fichiers dans le tableau à son tour comme exemple, introduisant le processus d'exécution de contrôle du code par des moyens récursifs.
Il est bon de l'appliquer à certains scénarios simples, tels que: nous pouvons utiliser cette méthode en enregistrant les données dans un tableau dans la base de données à tour.
Recursivement, certains problèmes de rappel asynchrones simples peuvent être résolus. Cependant, il semble toujours impuissant de gérer des rappels asynchrones complexes (comme la synchronisation des résultats de plusieurs opérations asynchrones).
Point magnifique: utilisez des bibliothèques tierces telles que Async, Q, promettez de gérer les rappels asynchrones
Afin de mieux gérer les rappels imbriqués, vous pouvez envisager d'utiliser certaines bibliothèques tierces qui traitent spécifiquement des asynchrones. Bien sûr, si vous avez la capacité, vous pouvez écrire un outil auxiliaire pour le traitement asynchrone par vous-même.
Les bibliothèques les plus couramment utilisées pour gérer le traitement asynchrone sont: Async, Q et Promise. À en juger par le site Web de NPMJS.org, Async est le plus populaire. J'ai déjà utilisé l'async, et c'est en effet assez pratique, et divers flux de contrôle de traitement asynchrones sont bien mis en œuvre.
Nous utiliserons Async pour traiter le code qui lit initialement deux fichiers en même temps, comme indiqué ci-dessous:
La copie de code est la suivante:
var async = require ('async')
, fs = require ('fs');
Async.Parallel ([
fonction (rappel) {
fs.readfile ('/ etc / passwd', fonction (err, data) {
if (err) callback (err);
rappel (null, données);
});
},
fonction (rappel) {
fs.readfile ('/ etc / passwd2', fonction (err, data2) {
if (err) callback (err);
rappel (null, data2);
});
}
],
fonction (err, résultats) {
// traite les données des données et des données2 ici, et le contenu de chaque fichier est obtenu à partir des résultats
});
Grâce au module asynchrone, le processus d'exécution asynchrone peut être bien contrôlé, ce qui peut également résoudre le problème des rappels en couches. Le code est plus clair qu'auparavant, mais il ne peut toujours pas être séparé de la fonction de rappel.
Pensez-y, ce serait formidable si vous pouvez gérer asynchrone sans utiliser de fonctions de rappel. Ensuite, parlons d'utiliser les nouvelles fonctionnalités d'ES6 pour atteindre cet objectif.
Point élégant: embrasser ES6, remplacer les fonctions de rappel et résoudre un problème d'enfer de rappel
Soit dit en passant, Ecmascript Harmony (ES6) a introduit beaucoup de nouvelles fonctionnalités à JS. Les étudiants qui ne savent pas grand-chose sur ES6 peuvent jeter un look Baidu seuls.
Pour utiliser les nouvelles fonctionnalités d'ES6 dans NodeJS, vous devez utiliser v0.11.x ou supérieur.
Cet article présente l'utilisation de la fonctionnalité du générateur au lieu de fonctions de rappel. Vous ne connaissez pas le générateur? Vous pouvez le vérifier ici.
Ici, nous utilisons deux modules Co et Thunkify, et nous utilisons la commande NPM Install pour l'installer.
Prenez le problème mentionné au début de cet article comme exemple. L'exemple de code utilisant la fonctionnalité du générateur est le suivant:
La copie de code est la suivante:
var fs = require ('fs')
, co = require ('co')
, thunkify = require ('thunkify');
var readFile = thunkify (fs.readfile);
co (fonction * () {
var test1 = rendement readFile ('test1.txt');
var test2 = rendement readFile ('test2.txt');
var test = test1.toString () + test2.ToString ();
console.log (test);
}) ();
Il est également très simple de gérer les exceptions dans le code, faites-le de cette façon:
La copie de code est la suivante:
essayer {
var test1 = rendement readFile ('test1.txt');
} catch (e) {
// gérer les exceptions ici
}
Ce genre de code est-il beaucoup plus élégant? N'est-il pas génial de gérer de manière asynchrone comme écrire du code synchrone?
Le cadre le plus populaire pour le développement Web dans le champ NodeJS est Express. Il convient de mentionner que le membre principal d'Express TJ, le grand maître des express, a dirigé un nouveau cadre Web - KOA, qui prétend être la prochaine génération de cadre de développement Web. KOA utilise vraiment la fonctionnalité du générateur ES6 pour nous aider à éviter de tomber dans des couches de rappels lors du développement du système Web.
Résumer
Citer une phrase de la promotion du projet FIBJS: moins de rappel, plus de filles - moins de rappels, plus de filles