Supposons que vous mainteniez une bibliothèque qui expose une fonction getData
. Vos utilisateurs l'appellent pour obtenir des données réelles:
var output = getData();
sous le capot, les données sont enregistrées dans un fichier, vous l'avez donc implémenté à l' getData
aide de Node.js intégré fs.readFileSync
. C'est évident à la fois getData
et ce fs.readFileSync
sont des fonctions de synchronisation. Un jour, on vous a dit de basculer la source de données sous-jacente vers un dépôt tel que MongoDB qui ne peut être accédé que de manière asynchrone. On vous a également dit d'éviter d'énerver vos utilisateurs,getData
API ne peut pas être modifiée pour renvoyer simplement une promesse ou exiger un paramètre de rappel. Comment répondez-vous aux deux exigences?
La fonction asynchrone utilisant le rappel / la promesse est l'ADN de JavasSript et Node.js. Toute application JS non triviale est probablement imprégnée de ce style de codage. Mais cette pratique peut facilement conduire à la soi-disant pyramide de callback of doom. Pire encore, si un code dans un appelant dans la chaîne d'appels dépend du résultat de la fonction asynchrone, ce code doit également être enveloppé dans la fonction de rappel, imposant une contrainte de style de codage à l'appelant. De temps en temps, je trouve le besoin d'encapsuler une fonction asynchrone (souvent fournie dans une bibliothèque tierce) dans une fonction de synchronisation afin d'éviter une refactorisation globale massive. La recherche d'une solution à ce sujet aboutissait généralement à des Node Fiberspackages ou npm dérivés. Mais Fibers ne peut tout simplement pas résoudre le problème auquel je suis confronté. Même l'exemple fourni par l'auteur de Fibers illustre la carence:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Sortie réelle:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Si la fonction Fibre transforme réellement le sommeil de la fonction asynchrone en synchronisation, la sortie doit être:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
J'ai créé un autre exemple simple dans JSFiddle et je cherche du code pour produire la sortie attendue. J'accepterai une solution qui ne fonctionne que dans Node.js, vous êtes donc libre d'exiger n'importe quel package npm même si vous ne travaillez pas dans JSFiddle.
Réponses:
deasync transforme la fonction async en synchronisation, implémentée avec un mécanisme de blocage en appelant la boucle d'événement Node.js au niveau de la couche JavaScript. En conséquence, deasync bloque uniquement l'exécution du code suivant sans bloquer tout le thread, ni entraîner une attente occupée. Avec ce module, voici la réponse au défi jsFiddle:
(avertissement: je suis le co-auteur de
deasync
. Le module a été créé après la publication de cette question et n'a trouvé aucune proposition viable.)la source
function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output);
et je m'attends à voir 3 secondes de différence dans la sortie de la date!Il existe également un module de synchronisation npm. qui est utilisé pour synchroniser le processus d'exécution de la requête.
Lorsque vous souhaitez exécuter des requêtes parallèles de manière synchrone, le nœud se limite à le faire car il n'attend jamais de réponse. et le module de synchronisation est parfait pour ce type de solution.
Exemple de code
lien de référence: https://www.npmjs.com/package/sync
la source
Oui. À l'intérieur de la fibre, la fonction attend avant de se connecter
ok
. Les fibres ne rendent pas les fonctions asynchrones synchrones, mais permettent d'écrire du code d'apparence synchrone qui utilise des fonctions asynchrones, puis s'exécutera de manière asynchrone dans un fichierFiber
.Vous ne pouvez pas. Il est impossible de rendre le code asynchrone synchrone. Vous devrez anticiper cela dans votre code global et l'écrire dans un style asynchrone depuis le début. Que vous enveloppiez le code global dans une fibre, utilisiez des promesses, des générateurs de promesses ou de simples rappels dépend de vos préférences.
Les promesses et les fibres peuvent le faire.
la source
fs
méthodes synchrones .Vous devez utiliser les promesses:
J'aime plus les définitions des fonctions fléchées. Mais toute chaîne de la forme "() => {...}" pourrait aussi être écrite comme "function () {...}"
Ainsi, topDog n'est pas asynchrone malgré l'appel d'une fonction async.
EDIT: Je me rends compte que la plupart du temps, vous devez envelopper une fonction asynchrone dans une fonction de synchronisation à l'intérieur d'un contrôleur. Pour ces situations, voici une astuce de fête:
En utilisant cela avec des rappels, vous pouvez faire un wrap qui n'utilise pas de promesses:
En appliquant cette astuce à un EventEmitter, vous pouvez obtenir les mêmes résultats. Définissez l'écouteur de l'EventEmitter où j'ai défini le rappel et émettez l'événement où j'ai appelé le rappel.
la source
Je ne trouve pas de scénario qui ne puisse pas être résolu en utilisant des fibres de nœuds. L'exemple que vous avez fourni à l'aide de nœuds-fibres se comporte comme prévu. La clé est d'exécuter tout le code pertinent à l'intérieur d'une fibre, afin que vous n'ayez pas à démarrer une nouvelle fibre dans des positions aléatoires.
Voyons un exemple: disons que vous utilisez un framework, qui est le point d'entrée de votre application (vous ne pouvez pas modifier ce framework). Ce framework charge les modules nodejs en tant que plugins et appelle certaines méthodes sur les plugins. Disons que ce cadre n'accepte que les fonctions synchrones et n'utilise pas de fibres par lui-même.
Il existe une bibliothèque que vous souhaitez utiliser dans l'un de vos plugins, mais cette bibliothèque est asynchrone et vous ne souhaitez pas non plus la modifier.
Le thread principal ne peut pas être généré lorsqu'aucune fibre n'est en cours d'exécution, mais vous pouvez toujours créer des plugins en utilisant des fibres! Créez simplement une entrée wrapper qui démarre tout le framework à l'intérieur d'une fibre, afin de pouvoir générer l'exécution à partir des plugins.
Inconvénient: si le framework utilise
setTimeout
ouPromise
s en interne, il échappera au contexte de la fibre. Cela peut être contourné en se moquantsetTimeout
,Promise.then
et tous les gestionnaires d'événements.C'est ainsi que vous pouvez produire une fibre jusqu'à ce que a
Promise
soit résolu. Ce code prend une fonction asynchrone (Promise retournant) et reprend la fibre lorsque la promesse est résolue:framework-entry.js
async-lib.js
mon-plugin.js
mon-entrée.js
Lorsque vous exécutez
node framework-entry.js
il lancera une erreur:Error: yield() called with no fiber running
. Si vous exécuteznode my-entry.js
cela fonctionne comme prévu.la source
La synchronisation du code Node.js est essentielle dans certains aspects tels que la base de données. Mais l'avantage réel de Node.js réside dans le code asynchrone. Comme il s'agit d'un seul thread non bloquant.
nous pouvons le synchroniser en utilisant une fonctionnalité importante Fiber () Utilisez await () et defer () nous appelons toutes les méthodes en utilisant await (). puis remplacez les fonctions de rappel par defer ().
Code Async normal, qui utilise les fonctions de rappel.
Synchronisez le code ci-dessus en utilisant Fiber (), await () et defer ()
J'espère que cela aidera. Merci
la source
De nos jours, ce modèle de générateur peut être une solution dans de nombreuses situations.
Voici un exemple d'invites de console séquentielles dans nodejs à l'aide de la fonction async readline.question:
la source
Vous ne devriez pas regarder ce qui se passe autour de l'appel qui crée la fibre, mais plutôt ce qui se passe à l' intérieur de la fibre. Une fois que vous êtes à l'intérieur de la fibre, vous pouvez programmer dans le style de synchronisation. Par exemple:
À l'intérieur de la fibre que vous appelez
f1
,f2
etsleep
comme s'ils étaient synchronisés.Dans une application Web classique, vous allez créer la fibre dans votre répartiteur de requêtes HTTP. Une fois que vous avez fait cela, vous pouvez écrire toute votre logique de gestion des demandes dans le style de synchronisation, même si elle appelle des fonctions asynchrones (fs, bases de données, etc.).
la source
while(true) handleNextRequest()
boucle. Emballer chaque gestionnaire de demande dans une fibre le ferait.J'ai eu du mal avec cela au début avec node.js et async.js est la meilleure bibliothèque que j'ai trouvée pour vous aider à gérer cela. Si vous souhaitez écrire du code synchrone avec node, l'approche est la suivante.
ce programme produira TOUJOURS ce qui suit ...
la source
async
fonctionne dans votre exemple b / c c'estmain
, qui ne se soucie pas de l'appelant. Imaginez que tout votre code est enveloppé dans une fonction qui est censée renvoyer le résultat de l'un de vos appels de fonction asynchrone. Il peut être facilement prouvé qu'il ne fonctionne pas en ajoutantconsole.log('return');
à la fin de votre code. Dans ce cas, la sortie dereturn
se produira aprèsin main
mais avantstep 1
.Javascript est un langage à thread unique, vous ne voulez pas bloquer tout votre serveur! Le code async élimine les conditions de concurrence en rendant les dépendances explicites.
Apprenez à aimer le code asynchrone!
Jetez un œil au
promises
code asynchrone sans créer une pyramide de l'enfer des rappels. Je recommande la bibliothèque promiseQ pour node.jshttp://howtonode.org/promises
EDIT: c'est de loin ma réponse la plus controversée, node a maintenant le mot-clé yield, qui vous permet de traiter le code asynchrone comme s'il était synchrone. http://blog.alexmaccaw.com/how-yield-will-transform-node
la source