Comment renvoyer la réponse d'un appel asynchrone ?
P粉668113768
2023-08-23 12:49:32
<p>Comment renvoyer une réponse/un résultat d'une fonction <code>foo</code> qui effectue une requête asynchrone ? </p>
<p>J'ai essayé de renvoyer la valeur du rappel et d'attribuer le résultat à une variable locale dans la fonction et de renvoyer cette variable, mais aucune de ces méthodes ne renvoie réellement de réponse - elles renvoient toutes <code>undefined< ou une variable La valeur initiale de <code>result</code>. </code></p><code>
<p><strong>Exemple de fonction asynchrone qui accepte un rappel</strong> (en utilisant la fonction <code>ajax</code>) : </p>
<pre class="brush:php;toolbar:false;">fonction foo() {
résultat var ;
$.ajax({
URL : '...',
succès : fonction (réponse) {
résultat = réponse ;
// renvoie la réponse ; // <- J'ai également essayé celui-là
}
});
return result ; // Il renvoie toujours « non défini »
}</pré>
<p><strong>Exemple d'utilisation de Node.js :</strong></p>
<pre class="brush:php;toolbar:false;">fonction foo() {
résultat var ;
fs.readFile("chemin/vers/fichier", fonction (erreur, données) {
résultat = données ;
// renvoie les données ; // <- J'ai aussi essayé celui-là
});
return result ; // Il renvoie toujours « non défini »
}</pré>
<p><strong>Exemple de bloc <code>then</code> utilisant Promise : </strong></p>
<pre class="brush:php;toolbar:false;">fonction foo() {
résultat var ;
fetch(url).then(fonction(réponse) {
résultat = réponse ;
// renvoie la réponse ; // <- J'ai également essayé celui-là
});
return result ; // Il renvoie toujours « non défini »
}</pré>
<p><br /></p></code>
Si vous n'utilisez pas jQuery dans votre code, cette réponse est pour vous
Votre code devrait ressembler à ceci :
Felix Kling a fait un excellent travailen écrivant la réponse pour les personnes utilisant jQuery pour AJAX, mais j'ai décidé de proposer une alternative aux personnes qui n'utilisent pas jQuery.
(Remarque, pour ceux qui utilisent la nouvelle
fetch
API, Angular ou Promise, j'ai ajouté une autre réponse ci-dessous )Problèmes auxquels vous êtes confronté
Voici un bref résumé de "l'explication de la question" d'une autre réponse, si vous n'êtes pas sûr après avoir lu ceci, veuillez lire cette réponse.
LeA dans AJAX signifie asynchrone. Cela signifie que l'envoi de la requête (ou plutôt la réception de la réponse) est supprimé du flux normal d'exécution. Dans votre exemple,
.send code>
立即返回,并且在调用您作为.send code>
success
回调传递的函数之前执行下一条语句return result;
renvoie immédiatement et l'instruction suivantereturn result;
est exécutée avant d'appeler la fonction que vous avez passée comme rappelsuccess
.code>.Cela signifie que lorsque vous revenez, l'écouteur que vous avez défini n'a pas encore été exécuté, ce qui signifie que la valeur que vous avez renvoyée n'a pas encore été définie.
Voici une analogie simple :
(violon)
Grâce à
a=5
部分尚未执行,因此返回的a
值为undefined
. AJAX se comporte de telle manière que vous renvoyez la valeur avant que le serveur n'ait la possibilité d'indiquer à votre navigateur quelle est la valeur.Une solution possible à ce problème consiste à réactivement écrire du code qui indique à votre programme quoi faire une fois le calcul terminé.
Cela s'appelle CPS. Fondamentalement, nous transmettons
getFive
une action à effectuer une fois terminée, et nous indiquons à notre code comment réagir lorsque l'événement se termine (comme notre appel AJAX, ou dans ce cas, un délai d'attente).L'utilisation est :
"5" apparaîtra à l'écran. (violon).
Solutions possibles
Il existe essentiellement deux manières de résoudre ce problème :
1. AJAX synchrone – Ne le faites pas ! !
Quant à l'AJAX synchrone, Ne le faites pas ! La réponse de Félix présente des arguments convaincants expliquant pourquoi c'est une mauvaise idée. Dans l'ensemble, cela gèle le navigateur de l'utilisateur jusqu'à ce que le serveur renvoie une réponse et crée une très mauvaise expérience utilisateur. Voici un autre bref résumé de MDN expliquant pourquoi :
Si vous devez faire cela, vous pouvez passer un drapeau. La méthode spécifique est la suivante :
2. Réorganiser le code
Faites en sorte que votre fonction accepte les rappels. Dans l'exemple de code, vous pouvez savoir comment
foo
接受回调。我们将告诉代码当foo
réagit lorsque est terminé.Donc :
devient :
Ici, nous transmettons une fonction anonyme, mais nous pourrions tout aussi bien transmettre une référence à une fonction existante, la faisant ressembler à :
Pour plus de détails sur la façon de réaliser ce type de conception de rappel, consultez la réponse de Félix.
Maintenant, définissons foo lui-même pour fonctionner en conséquence
(violon)
Nous avons maintenant la fonction foo qui accepte une action à exécuter lorsque AJAX se termine avec succès. Nous pouvons étendre davantage cette fonctionnalité en vérifiant si l'état de la réponse n'est pas 200 et en prenant les mesures appropriées (création d'un gestionnaire d'échec, etc.). Cela a effectivement résolu notre problème.
Si vous avez toujours du mal à comprendre cela, Lisez AJAX pour un guide pour démarrer sur MDN.
Question
LeA dans Ajax signifie asynchrone. Cela signifie que l'envoi de la requête (ou plutôt la réception de la réponse) est supprimé du flux normal d'exécution. Dans votre exemple,
$.ajax
立即返回,并且下一条语句return result;
在您作为success
le rappel est passé avant même que la fonction ne soit appelée.Voici une analogie qui, espérons-le, rendra plus claire la différence entre les flux synchrones et asynchrones :
Sync
Imaginez que vous appeliez un ami et lui demandiez de trouver des informations pour vous. Même si cela peut prendre un certain temps, vous attendez près du téléphone, le regard dans le vide, jusqu'à ce que votre ami vous donne la réponse dont vous avez besoin.
La même chose se produit lorsque vous effectuez un appel de fonction contenant du code "normal":
Bien que tout code après
findItem
可能需要很长时间才能执行,但var item = findItem();
doive attendre jusqu'à ce que la fonction renvoie le résultat.Asynchrone
Vous appelez à nouveau votre ami pour la même raison. Mais cette fois, vous lui dites que vous êtes anxieux et qu'il devrait vous rappeler en utilisant votre téléphone portable. Vous raccrochez, quittez la maison et faites ce que vous aviez prévu de faire. Une fois que votre ami vous rappelle, vous traitez les informations qu'il vous a fournies.
C'est exactement ce qui se passe lorsque vous faites une requête Ajax.
N'attend pas de réponse, mais continue l'exécution immédiatement et exécute l'instruction après l'appel Ajax. Afin d'obtenir enfin la réponse, vous devez fournir une fonction qui est appelée après la réception de la réponse, un rappel (vous avez remarqué quelque chose ? Un rappel ?). Toutes les instructions après cet appel seront exécutées avant que le rappel ne soit appelé.
Solution
Adoptez la nature asynchrone de JavaScript ! Bien que certaines opérations asynchrones fournissent des contreparties synchrones (comme le fait "Ajax"), leur utilisation est généralement déconseillée, notamment dans un contexte de navigateur.
Pourquoi est-ce mauvais, demandez-vous ?
JavaScript s'exécute dans le thread de l'interface utilisateur du navigateur et tout processus de longue durée peut verrouiller l'interface utilisateur, la rendant insensible. De plus, il existe une limite supérieure au temps d'exécution de JavaScript et le navigateur demandera à l'utilisateur s'il doit poursuivre l'exécution.
Tout cela conduit à une très mauvaise expérience utilisateur. L'utilisateur ne pourra pas savoir si tout fonctionne correctement. De plus, l’effet sera pire pour les utilisateurs dont la vitesse Internet est plus lente.
Nous présentons ci-dessous trois solutions différentes qui s'appuient toutes les unes sur les autres :
async/await
(ES2017+, fonctionne dans les anciens navigateurs si vous utilisez un transpileur ou un régénérateur)then() 的 Promise
(ES2015+, fonctionne dans les anciens navigateurs si vous utilisez l'une des nombreuses bibliothèques Promise)Ces trois fonctionnalités sont disponibles dans les navigateurs actuels et Node 7+.
ES2017+ : Utilisez
async/await 进行承诺
La version 2017 d'ECMAScript a introduit la prise en charge au niveau de la syntaxe pour les fonctions asynchrones. Avec
async
和await
vous pouvez écrire de manière asynchrone dans un "style synchrone". Le code est toujours asynchrone, mais plus facile à lire/comprendre.
async renvoient toujours une promesse.async/await
构建在 Promise 之上:async
函数始终返回 Promise。await
Construit sur une promesse : les fonctionsawait "déverrouille" une promesse et produit soit la valeur à laquelle la promesse est résolue, soit génère une erreur si la promesse est rejetée.
: Vous ne pouvez utiliserasync
函数或 JavaScript 模块。模块外部不支持顶级await
,因此您可能必须创建异步 IIFE (立即调用函数表达式)来启动异步
IMPORTANTawait que dans les fonctions async ou Modules JavaScript
async. Le niveau supérieur await
n'est pas pris en charge en dehors du module, vous devrez donc peut-être créer un IIFE asynchrone (Expression de fonction immédiatement invoquée ) pour démarrer le contexte async (si vous n'utilisez pas de modules).Vous pouvez en savoir plus sur
et
findItem()
await. Voici un exemple détaillant la fonction delayed
nodeasync/await
findItem() ci-dessus : Les versions actuelles de browser etprennent en charge
. Vous pouvez également convertir votre code en ES5 à l'aide de regenerator
(ou d'outils utilisant le régénérateur) pour prendre en charge des environnements plus anciens tels queBabel
). 🎜 🎜 🎜Laissez la fonction accepter les rappels🎜🎜 🎜Le rappel a lieu lorsque la fonction 1 est transmise à la fonction 2. La fonction 2 peut appeler la fonction 1 lorsqu'elle est prête. Dans le contexte d'un processus asynchrone, le rappel est appelé chaque fois que le processus asynchrone se termine. Normalement, les résultats sont transmis au rappel. 🎜Dans l'exemple de la question, vous pouvez effectuer
foo
接受回调并将其用作success
un rappel. Alors çaest devenu
Ici, nous définissons une fonction "inline", mais vous pouvez passer n'importe quelle référence de fonction :
foo
lui-même est défini comme suit :callback
fera référence à la fonction à laquelle nous avons passécallback
将引用我们调用时传递给foo
的函数,并将其传递给success
。 IE。一旦Ajax请求成功,$.ajax
将调用callback
并将响应传递给回调(可以用result
lorsque nous l'avons appelée, et la transmettra àsuccess
. c'est à dire. Une fois la requête Ajax réussie,$.ajax
appelleracallback
et transmettra la réponse au rappel (qui peut être référencée avecresult
, puisque c'est ainsi que nous définissons le rappel (The way).Vous pouvez également traiter la réponse avant de la transmettre au rappel :
Écrire du code à l'aide de rappels est plus facile qu'il n'y paraît. Après tout, JavaScript dans les navigateurs est largement piloté par les événements (événements DOM). Recevoir une réponse Ajax n'est rien de plus qu'un événement. Des difficultés peuvent survenir lorsque vous devez utiliser du code tiers, mais la plupart des problèmes peuvent être résolus en pensant simplement au flux de l'application.
ES2015+ : avec then()的 Promise >
Promise API est une nouvelle fonctionnalité ECMAScript 6 (ES2015), mais elle dispose déjà d'un bon support de navigateur. Il existe également de nombreuses bibliothèques qui implémentent l'API Promises standard et fournissent des méthodes supplémentaires pour simplifier l'utilisation et la composition des fonctions asynchrones (par exemple, Bluebird).
La promesse est un conteneur de valeurs futures. Lorsqu'une promesse reçoit une valeur (résolue) ou est annulée (rejetée), elle avertit tous les « auditeurs » qui souhaitent accéder à la valeur.
L'avantage par rapport aux rappels normaux est qu'ils vous permettent de découpler votre code et sont plus faciles à écrire.
Voici un exemple d'utilisation de Promise :