Comment appeler une fonction JavaScript asynchrone et bloquer l'appelant d'origine
J'ai une situation intéressante que ma habituellement malin esprit n'a pas été en mesure de trouver une solution 🙂 Voici la situation...
J'ai une classe qui a une méthode get ()... cette méthode est appelée à se stocker les préférences de l'utilisateur... ce qu'il fait est d'appels sur certains fournisseur sous-jacent à réellement obtenir les données... comme l'écrit maintenant, c'est l'appel à un prestataire qui parle des cookies... alors, get() appelle providerGet() disons, providerGet() renvoie une valeur et get() passe ainsi que de l'appelant. L'appelant attend une réponse avant de continuer son travail évidemment.
Ici la partie la plus délicate... maintenant, je suis en train de mettre en œuvre un fournisseur qui est asychronous dans la nature (à l'aide de local de stockage dans ce cas)... donc, providerGet() serait de retour tout de suite, avoir envoyé un appel local de stockage qui, quelques temps plus tard, une fonction de rappel qui lui a été transmis... mais, depuis providerGet() déjà retourné, et n'a donc get() maintenant, par extension, à l'origine appelé, il est évident qu'elle n'a pas retourné le réel des données récupérées.
Donc, la question est simple est-il un moyen de "bloquer" le retour de providerGet() jusqu'à ce que le asychronous retours d'appel? Notez que pour mes fins, je ne suis pas concerné par la performance des implications que cela peut avoir, j'essaie juste de comprendre comment le faire fonctionner.
Je ne pense pas qu'il y a un moyen, certes, je sais que je n'ai pas été en mesure de venir avec elle... donc je voulais jeter un œil et voir ce que les autres peuvent venir avec 🙂
edit: je suis en train d'apprendre maintenant que le cœur du problème, le fait que le web API sql est asychronous, peut-être une solution... se trouve qu'il existe une version synchrone de l'API ainsi, quelque chose que je ne savais pas... je suis en train de lire à travers docs maintenant à voir comment l'utiliser, mais qui permettrait de résoudre le problème bien puisque la seule raison providerGet() a été écrit asychronously à tous, c'était pour permettre au fournisseur... le code que get() est une partie de mon propre couche d'abstraction au-dessus de différents fournisseurs de données (cookies, web, sql, localStorage, etc) de sorte que le plus petit dénominateur commun est de gagner, ce qui signifie que si l'un est asychronous ils ont TOUS à être asychronous... le seul qui a est web sql... donc si il y a un moyen de le faire de manière synchrone mon point discutable (encore une question intéressante, de manière générique, je pense que si)
edit2: Ah bien, sans y aider, il semble... me semble que la version synchrone de l'API n'est pas implémenté dans n'importe quel navigateur et même si c'était il est spécifié qu'il ne peut être utilisé à partir de threads de travail, de sorte que cela ne semble pas comme il faudrait aider de toute façon. Bien que, la lecture de certains autres choses, il sonne comme il ya une façon de s'en sortir de cette astuce en utilisant la récursivité... je suis de jeter ensemble des tests de code de maintenant, je vais le poster si/quand-je obtenir ce travail, semble être un moyen très intéressant pour obtenir autour de la situation d'une manière générique.
edit3: Comme pour mon commentaires ci-dessous, il n'y a vraiment aucun moyen de faire exactement ce que je voulais. La solution que je vais à résoudre mon problème immédiat est tout simplement de ne pas permettre l'utilisation de web SQL pour le stockage de données. Ce n'est pas la solution idéale, mais que cette spécification est en perpétuelle évolution et ne sont pas largement mis en œuvre, de toute façon c'est pas la fin du monde... j'espère quand son correctement pris en charge la version synchrone sera disponible et je peux brancher un nouveau fournisseur et être bon d'aller. De manière générique, cependant, il ne semble pas être un moyen de tirer de ce miracle... confirme ce que j'attendais c'était le cas, mais j'ai eu tort cette fois-ci 🙂
source d'informationauteur Frank W. Zammetti | 2011-12-09
Vous devez vous connecter pour publier un commentaire.
Non, vous ne pouvez pas bloquer jusqu'à ce que le asynch appel se termine. C'est aussi simple que cela.
Cela sonne comme vous le savez peut-être déjà, mais si vous souhaitez utiliser asynchrone des appels ajax, alors vous avez à restructurer la façon dont votre code est utilisé. Vous ne pouvez pas avoir juste un .méthode get() qui fait un appel ajax asynchrone, les blocs jusqu'à ce qu'il complète et renvoie le résultat. Le modèle le plus couramment utilisé dans ces cas (regardez toutes de Google Api javascript qui n'mise en réseau, par exemple) est à demander à l'appelant de vous passer d'une fonction d'achèvement. L'appel à
.get()
va commencer l'opération asynchrone et les retourner immédiatement. Lorsque l'opération est terminée, l'achèvement de la fonction sera appelée. L'appelant doit structurer leur code en conséquence.Vous ne peut tout simplement pas écrire droit, de procédure séquentielle du code javascript lors de l'utilisation asynchrone de réseautage comme:
La conception la plus courante motif est comme ceci:
Si votre problème est l'appel de plusieurs couches de profondeur, puis les rappels peuvent être transmis à différents niveaux et invoquée en cas de besoin.
frayer un webworker thread pour faire l'opération asynchrone pour vous.
passer info il a besoin pour faire le travail en plus d'un id unique.
le truc, c'est de l'avoir envoyer le résultat à un serveur web lorsqu'elle se termine.
pendant ce temps...la fonction qui a donné naissance à la webworker envoie une requête ajax vers le même serveur
utilisation de la machine synchrone drapeau de l'objet xmlhttprequest(oui, il a un synchrones option). depuis, il bloquera jusqu'à ce que la requête http est terminée, vous pouvez juste avoir votre serveur script de sondage la base de données pour les mises à jour ou que ce soit jusqu'à ce que le résultat a été envoyée.
moche, je sais. mais il serait bloc, sans accaparer cpu 😀
fondamentalement
Pourquoi ne pas simplement avoir l'appelant d'origine passe dans un rappel de sa propre à
get()
? Cette fonction de rappel devrait contenir le code qui s'appuie sur la réponse.La
get()
méthode avant le rappel àproviderGet()
qui serait alors de l'appeler lorsqu'il appelle ses propres rappel.Le résultat de l'extraction serait passé à l'appelant d'origine du rappel.
Lorsque votre méthode async commence, je voudrais ouvrir une sorte de dialogue modale (que l'utilisateur ne peut pas fermer) pour leur dire que la demande est en cours. Lorsque la demande de finitions, fermer la modale dans votre fonction de rappel.
Une façon possible de faire, c'est avec jqModalmais cela nécessiterait le chargement de jQuery dans votre projet. Je ne suis pas sûr si c'est une option pour vous ou pas.
C'est moche, mais de toute façon je pense que la question est kindof ce qui implique une vilaine solution est souhaitée...
Sinon, pour éviter d'envoyer les données sur le réseau, vous pourriez avoir votre iframe encoder le résultat dans une toile d'image de synthèse que le navigateur met en cache (similaire à l'approche de Zombie cookie aurait utilisé). Alors votre script de blocage serait essaient continuellement de charger cette image, encore et encore (avec quelques petites réseau généré retard sur chaque demande) jusqu'à ce que la version mise en cache est disponible, ce qui peut se reconnaître à travers un drapeau que vous avez défini pour indiquer qu'il est fait.