Tout d'abord, il s'agit d'un cas très spécifique de le faire de la mauvaise façon exprès pour moderniser un appel asynchrone dans une base de code très synchrone qui fait plusieurs milliers de lignes et le temps ne permet pas actuellement de faire les changements pour "faire bien. " Cela fait mal à chaque fibre de mon être, mais la réalité et les idéaux ne s'imbriquent souvent pas. Je sais que ça craint.
OK, cela à l'écart, comment puis-je faire en sorte que je puisse:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
Les exemples (ou leur absence) utilisent tous des bibliothèques et / ou des compilateurs, tous deux non viables pour cette solution. J'ai besoin d'un exemple concret de la façon de le faire bloquer (par exemple, NE PAS laisser la fonction doSomething jusqu'à ce que le rappel soit appelé) SANS geler l'interface utilisateur. Si une telle chose est possible dans JS.
la source
Réponses:
D'ACCORD. mais vous devez vraiment le faire de la bonne façon ... ou autre
Non, il est impossible de bloquer le JavaScript en cours d'exécution sans bloquer l'interface utilisateur.
Étant donné le manque d'informations, il est difficile de proposer une solution, mais une option peut être de demander à la fonction appelante d'effectuer une interrogation pour vérifier une variable globale, puis de définir le rappel
data
sur la valeur globale.Tout cela suppose que vous pouvez modifier
doSomething()
. Je ne sais pas si c'est dans les cartes.S'il peut être modifié, je ne sais pas pourquoi vous ne passeriez pas simplement un rappel
doSomething()
pour être appelé de l'autre rappel, mais je ferais mieux de m'arrêter avant d'avoir des ennuis. ;)Oh, que diable. Vous avez donné un exemple qui suggère que cela peut être fait correctement, donc je vais montrer cette solution ...
Étant donné que votre exemple inclut un rappel qui est passé à l'appel asynchrone, la bonne façon serait de passer une fonction à appeler
doSomething()
à partir du rappel.Bien sûr, si c'est la seule chose que le rappel fait, vous passeriez simplement
func
directement ...la source
callback
fonction à lamyAsynchronousCall
fonction, qui fait son travail asynchrone et appelle le rappel une fois terminé. Voici une démo.Les fonctions asynchrones , une fonctionnalité d'ES2017 , permettent de synchroniser le code asynchrone en utilisant des promesses (une forme particulière de code asynchrone) et le
await
mot clé. Notez également dans les exemples de code ci-dessous le mot-cléasync
devant lefunction
mot-clé qui signifie une fonction asynchrone / attente. Leawait
mot-clé ne fonctionnera pas sans être dans une fonction pré-fixée avec leasync
mot - clé. Comme il n'y a actuellement aucune exception à cela, cela signifie qu'aucune attente de niveau supérieur ne fonctionnera (le niveau supérieur attend, ce qui signifie une attente en dehors de toute fonction). Bien qu'il existe une proposition de haut niveauawait
.ES2017 a été ratifié (c'est-à-dire finalisé) en tant que norme pour JavaScript le 27 juin 2017. L'attente asynchrone peut déjà fonctionner dans votre navigateur, mais sinon, vous pouvez toujours utiliser la fonctionnalité à l'aide d'un transpilateur javascript comme babel ou traceur . Chrome 55 prend entièrement en charge les fonctions asynchrones. Donc, si vous avez un navigateur plus récent, vous pourrez peut-être essayer le code ci-dessous.
Voir le tableau de compatibilité es2017 de kangax pour la compatibilité du navigateur.
Voici un exemple de fonction d'attente asynchrone appelée
doAsync
qui prend trois pauses d'une seconde et imprime le décalage horaire après chaque pause à partir de l'heure de début:Lorsque le mot-clé wait est placé avant une valeur promise (dans ce cas, la valeur promise est la valeur retournée par la fonction doSomethingAsync), le mot-clé wait suspendra l'exécution de l'appel de fonction, mais ne suspendra aucune autre fonction et continuera exécuter un autre code jusqu'à ce que la promesse soit résolue. Une fois la promesse résolue, elle déballera la valeur de la promesse et vous pouvez penser que l'expression attendre et promettre est désormais remplacée par cette valeur non emballée.
Ainsi, puisque wait s'arrête juste attend puis décompresse une valeur avant d'exécuter le reste de la ligne, vous pouvez l'utiliser dans les boucles et les appels de fonction internes comme dans l'exemple ci-dessous qui collecte les différences de temps attendues dans un tableau et imprime le tableau.
La fonction asynchrone elle-même renvoie une promesse afin que vous puissiez l'utiliser comme une promesse avec un chaînage comme je le fais ci-dessus ou dans une autre fonction d'attente asynchrone.
La fonction ci-dessus attendrait chaque réponse avant d'envoyer une autre demande si vous souhaitez envoyer les demandes simultanément, vous pouvez utiliser Promise.all .
Si la promesse est éventuellement rejetée, vous pouvez l'encapsuler dans un catch catch ou ignorer le try catch et laisser l'erreur se propager à l'appel des fonctions async / wait. Vous devez faire attention à ne pas laisser les erreurs de promesse non gérées, en particulier dans Node.js. Voici quelques exemples qui montrent comment fonctionnent les erreurs.
Si vous allez ici, vous pouvez voir les propositions finies pour les prochaines versions d'ECMAScript.
Une alternative à cela qui peut être utilisée avec seulement ES2015 (ES6) est d'utiliser une fonction spéciale qui encapsule une fonction de générateur. Les fonctions génératrices ont un mot-clé yield qui peut être utilisé pour répliquer le mot-clé wait avec une fonction environnante. Le mot-clé yield et la fonction de générateur sont beaucoup plus généraux et peuvent faire beaucoup plus de choses que ce que fait la fonction d'attente asynchrone. Si vous voulez une enveloppe de fonction de générateur qui peut être utilisé pour async répliquées attendre que je vérifierais co.js . Par ailleurs, la fonction de co, tout comme les fonctions d'attente asynchrone, renvoie une promesse. Honnêtement, à ce stade, la compatibilité du navigateur est à peu près la même pour les fonctions de générateur et les fonctions asynchrones, donc si vous voulez juste la fonctionnalité d'attente asynchrone, vous devez utiliser les fonctions Async sans co.js.
La prise en charge du navigateur est en fait assez bonne maintenant pour les fonctions Async (à partir de 2017) dans tous les principaux navigateurs actuels (Chrome, Safari et Edge) sauf IE.
la source
Jetez un œil aux promesses JQuery:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Refactoriser le code:
la source
dfd.notify(data)
àdfd.resolve(data)
Il existe une solution de contournement intéressante sur http://taskjs.org/
Il utilise des générateurs qui sont nouveaux en javascript. Il n'est donc actuellement pas implémenté par la plupart des navigateurs. Je l'ai testé dans Firefox, et pour moi, c'est une bonne façon d'envelopper la fonction asynchrone.
Voici un exemple de code du projet GitHub
la source
Vous pouvez forcer le JavaScript asynchrone dans NodeJS à être synchrone avec sync-rpc .
Cependant, cela gèlera certainement votre interface utilisateur, donc je suis toujours un naysayer pour savoir s'il est possible de prendre le raccourci dont vous avez besoin. Il n'est pas possible de suspendre le One And Only Thread en JavaScript, même si NodeJS vous permet parfois de le bloquer. Aucun rappel, événement, rien d'asynchrone ne pourra être traité jusqu'à ce que votre promesse soit résolue. Donc, à moins que vous, le lecteur, n'ayez une situation inévitable comme l'OP (ou, dans mon cas, écrivez un script shell glorifié sans rappels, événements, etc.), NE FAITES PAS CECI!
Mais voici comment procéder:
./calling-file.js
./my-asynchronous-call.js
LIMITES:
Ce sont à la fois une conséquence de la façon dont
sync-rpc
est mis en œuvre, qui est en abusantrequire('child_process').spawnSync
:JSON.stringify
, donc les fonctions et les propriétés non énumérables comme les chaînes de prototypes seront perdues.la source
Vous pouvez également le convertir en rappels.
la source
Ce que vous voulez est maintenant possible. Si vous pouvez exécuter le code asynchrone dans un travailleur de service et le code synchrone dans un travailleur Web, vous pouvez demander au travailleur Web d'envoyer un XHR synchrone au travailleur de service, et pendant que le travailleur de service fait les choses asynchrones, le travailleur Web le fil attendra. Ce n'est pas une excellente approche, mais cela pourrait fonctionner.
la source
L'idée que vous espérez réaliser peut être rendue possible si vous modifiez un peu l'exigence
Le code ci-dessous est possible si votre runtime prend en charge la spécification ES6.
En savoir plus sur les fonctions asynchrones
la source
SyntaxError: await is only valid in async functions and async generators
. Sans oublier que param1 n'est pas défini (et même pas utilisé).