


Explication détaillée de la solution de synchronisation/asynchrone async+wait d'ES6
Cet article présente principalement l'explication détaillée de la solution de synchronisation/asynchrone async+await d'ES6. Cet article utilise la manière la plus concise de débloquer async + wait. Ceux qui sont intéressés peuvent en savoir plus
La programmation asynchrone a toujours été. La programmation JavaScript est devenue une question majeure. Concernant les solutions asynchrones, ES6 a d'abord vu émerger Promise basée sur la gestion d'état, puis la fonction Generator + co function, et enfin la solution ES7 async + wait.
Cet article s'efforce de débloquer async + wait de la manière la plus concise.
Plusieurs scénarios de programmation asynchrone
Commencez par une question courante : Comment imprimer la séquence d'itérations de manière asynchrone dans une boucle for ?
Nous pouvons facilement penser à utiliser des fermetures ou la portée au niveau du bloc let spécifiée dans ES6 pour répondre à cette question.
for (let val of [1, 2, 3, 4]) { setTimeout(() => console.log(val),100); } // => 预期结果依次为:1, 2, 3, 4
Ce qui est décrit ici est un événement asynchrone qui se produit de manière uniforme, et ils sont mis en file d'attente dans la file d'attente asynchrone dans un ordre prédéterminé en attente d'exécution.
Si l'asynchronie ne se produit pas uniformément, alors l'ordre dans lequel ils sont enregistrés dans la file d'attente asynchrone sera dans le désordre.
for (let val of [1, 2, 3, 4]) { setTimeout(() => console.log(val), 100 * Math.random()); } // => 实际结果是随机的,依次为:4, 2, 3, 1
Les résultats renvoyés sont dans le désordre et incontrôlables, ce qui est l'asynchrone le plus réaliste. Mais une autre situation est que dans une boucle, que devez-vous faire si vous souhaitez que l'exécution asynchrone précédente soit terminée et que l'exécution asynchrone suivante soit à nouveau exécutée ?
for (let val of ['a', 'b', 'c', 'd']) { // a 执行完后,进入下一个循环 // 执行 b,依此类推 }
N'est-ce pas juste plusieurs « séries » asynchrones !
La méthode consistant à imbriquer les opérations asynchrones dans le rappel puis à rappeler résout ce problème ! Alternativement, utiliser Promise + then() pour imbriquer les couches peut également résoudre le problème. Cependant, si vous insistez pour écrire cette méthode d'imbrication en boucle, je crains que cela ne pose encore beaucoup de problèmes. Je me demande, existe-t-il un meilleur moyen ?
Solution de synchronisation asynchrone
Imaginez si vous souhaitez envoyer un lot de données au serveur, seul le lot précédent est envoyé avec succès (c'est-à-dire que le serveur renvoie un réponse réussie), alors seulement commence l'envoi du prochain lot de données, sinon l'envoi est terminé. Il s'agit d'un exemple typique d'"opérations asynchrones interdépendantes dans une boucle for".
Évidemment, cet asynchrone "série" peut en fait être considéré comme une synchronisation. Cela prend plus de temps qu'un asynchrone dans le désordre. Logiquement parlant, nous voulons que le programme s'exécute de manière asynchrone, juste pour « ignorer » le blocage et passer moins de temps. Mais au contraire, si nous avons besoin d’une série de « séries » asynchrones, comment bien programmer ?
Pour cet asynchrone "série", ES6 peut facilement résoudre ce problème.
async function task () { for (let val of [1, 2, 3, 4]) { // await 是要等待响应的 let result = await send(val); if (!result) { break; } } } task();
Littéralement, c'est ce cycle. Une fois les résultats obtenus, le cycle suivant sera réalisé. Par conséquent, la boucle est mise en pause (« bloquée ») à chaque exécution jusqu'à la fin de la boucle. Cette implémentation de codage élimine efficacement le problème de « l'enfer des rappels » imbriqués et réduit les difficultés cognitives.
C'est la solution pour synchroniser les problèmes asynchrones. Concernant cette solution, si Promise résout principalement le problème des rappels asynchrones, alors async + wait résout principalement le problème de la synchronisation des problèmes asynchrones et réduit la charge cognitive de la programmation asynchrone.
async + wait "différent à l'extérieur mais pareil à l'intérieur"
Quand je suis entré en contact avec cette API plus tôt, j'ai regardé la lourde documentation et Je pensais que async + wait était principalement utilisé pour résoudre le problème. Les problèmes asynchrones sont synchrones.
Ce n’est pas le cas. Comme le montre l'exemple ci-dessus : le mot-clé async déclare une fonction asynchrone. Il y a une ligne d'instructions wait dans le corps de cette fonction asynchrone, qui notifie que le comportement est exécuté de manière synchrone et que les codes adjacents ci-dessus et ci-dessous sont exécutés. ligne par ligne dans l’ordre.
Pour traduire à nouveau cette chose formelle, c'est :
1 Une fois la fonction asynchrone exécutée, un objet de promesse est toujours renvoyé
2. est synchrone
Parmi eux, 1 montre que de l'extérieur, la méthode tâche renvoie un objet Promise après exécution. Parce qu'elle renvoie une Promise, on peut comprendre que la tâche est une méthode asynchrone. Il ne fait aucun doute qu'il est utilisé comme ceci :
task().then((val) => {alert(val)}) .then((val) => {alert(val)})
2 montre qu'à l'intérieur de la fonction tâche, l'asynchrone a été "coupé" en synchronisation. Le tout n’est qu’une fonction qui prend un peu de temps à s’exécuter.
En synthétisant 1 et 2, d'un point de vue formel, "la tâche dans son ensemble est une fonction asynchrone, et toute la partie interne est synchrone", ce qui est dit "différent à l'extérieur mais le pareil à l'intérieur".
La fonction entière est une fonction asynchrone, ce qui n'est pas difficile à comprendre. En termes d'implémentation, autant l'inverser. Au niveau du langage, lorsque le mot-clé async est appelé, une promesse est obligatoirement ajoutée à la fin de l'exécution de la fonction. Le retour :
<🎜. >
async fn () { let result; // ... //末尾返回 promise return isPromise(result)? result : Promise.resolve(undefined); }
秉承本次《重读 ES6》系列的原则,不过多追求理解细节和具体实现过程。我们继续巩固一下这个 “形式化” 的理解。
async + await 的进一步理解
有这样的一个异步操作 longTimeTask,已经用 Promise 进行了包装。借助该函数进行一系列验证。
const longTimeTask = function (time) { return new Promise((resolve, reject) => { setTimeout(()=>{ console.log(`等了 ${time||'xx'} 年,终于回信了`); resolve({'msg': 'task done'}); }, time||1000) }) }
async 函数的执行情况
如果,想查看 async exec1 函数的返回结果,以及 await 命令的执行结果:
const exec1 = async function () { let result = await longTimeTask(); console.log('result after long time ===>', result); } // 查看函数内部执行顺序 exec1(); // => 等了 xx 年,终于回信了 // => result after long time ===> Object {msg: "task done"} //查看函数总体返回值 console.log(exec1()); // => Promise {[[PromiseStatus]]: "pending",...} // => 同上
以上 2 步执行,清晰的证明了 exec1 函数体内是同步、逐行逐行执行的,即先执行完异步操作,然后进行 console.log() 打印。而 exec1() 的执行结果就直接是一个 Promise,因为它最先会蹦出来一串 Promise ...,然后才是 exec1 函数的内部执行日志。
因此,所有验证,完全符合 整体是一个异步函数,内部整个是同步的 的总结。
await 如何执行其后语句?
回到 await ,看看它是如何执行其后边的语句的。假设:让 longTimeTask() 后边直接带 then() 回调,分两种情况:
1)then() 中不再返回任何东西
2) then() 中继续手动返回另一个 promise
const exec2 = async function () { let result = await longTimeTask().then((res) => { console.log('then ===>', res.msg); res.msg = `${res.msg} then refrash message`; // 注释掉这条 return 或 手动返回一个 promise return Promise.resolve(res); }); console.log('result after await ===>', result.msg); } exec2(); // => 情况一 TypeError: Cannot read property 'msg' of undefined // => 情况二 正常
首先,longTimeTask() 加上再多得 then() 回调,也不过是放在了它的回调列队 queue 里了。也就是说,await 命令之后始终是一条 表达式语句,只不过上述代码书写方式比较让人迷惑。(比较好的实践建议是,将 longTimeTask 方法身后的 then() 移入 longTimeTask 函数体封装起来)
其次,手动返回另一个 promise 和什么也不返回,关系到 longTimeTask() 方法最终 resolve 出去的内容不一样。换句话说,await 命令会提取其后边的promise 的 resolve 结果,进而直接导致 result 的不同。
值得强调的是,await 命令只认 resolve 结果,对 reject 结果报错。不妨用以下的 return 语句替换上述 return 进行验证。
return Promise.reject(res);
最后
其实,关于异步编程还有很多可以梳理的,比如跨模块的异步编程、异步的单元测试、异步的错误处理以及什么是好的实践。All in all, 限于篇幅,不在此汇总了。最后,async + await 确实是一个很优雅的方案。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Explication détaillée de la fonction mode en C++ En statistiques, le mode fait référence à la valeur qui apparaît le plus fréquemment dans un ensemble de données. En langage C++, nous pouvons trouver le mode dans n’importe quel ensemble de données en écrivant une fonction de mode. La fonction mode peut être implémentée de nombreuses manières différentes, deux des méthodes couramment utilisées seront présentées en détail ci-dessous. La première méthode consiste à utiliser une table de hachage pour compter le nombre d'occurrences de chaque nombre. Tout d’abord, nous devons définir une table de hachage avec chaque nombre comme clé et le nombre d’occurrences comme valeur. Ensuite, pour un ensemble de données donné, nous exécutons

Le système d'exploitation Windows est l'un des systèmes d'exploitation les plus populaires au monde et sa nouvelle version Win11 a beaucoup attiré l'attention. Dans le système Win11, l'obtention des droits d'administrateur est une opération importante. Les droits d'administrateur permettent aux utilisateurs d'effectuer davantage d'opérations et de paramètres sur le système. Cet article présentera en détail comment obtenir les autorisations d'administrateur dans le système Win11 et comment gérer efficacement les autorisations. Dans le système Win11, les droits d'administrateur sont divisés en deux types : administrateur local et administrateur de domaine. Un administrateur local dispose de tous les droits d'administration sur l'ordinateur local

Explication détaillée de l'opération de division dans OracleSQL Dans OracleSQL, l'opération de division est une opération mathématique courante et importante, utilisée pour calculer le résultat de la division de deux nombres. La division est souvent utilisée dans les requêtes de bases de données. Comprendre le fonctionnement de la division et son utilisation dans OracleSQL est donc l'une des compétences essentielles des développeurs de bases de données. Cet article discutera en détail des connaissances pertinentes sur les opérations de division dans OracleSQL et fournira des exemples de code spécifiques pour référence aux lecteurs. 1. Opération de division dans OracleSQL

Explication détaillée de la fonction reste en C++ En C++, l'opérateur reste (%) est utilisé pour calculer le reste de la division de deux nombres. Il s'agit d'un opérateur binaire dont les opérandes peuvent être n'importe quel type entier (y compris char, short, int, long, etc.) ou un type nombre à virgule flottante (tel que float, double). L'opérateur reste renvoie un résultat du même signe que le dividende. Par exemple, pour l'opération de reste des entiers, nous pouvons utiliser le code suivant pour implémenter : inta=10;intb=3;

Explication détaillée de l'utilisation de la fonction Vue.nextTick et de son application dans les mises à jour asynchrones. Dans le développement de Vue, nous rencontrons souvent des situations où les données doivent être mises à jour de manière asynchrone. Par exemple, les données doivent être mises à jour immédiatement après la modification du DOM ou des opérations associées. à effectuer immédiatement après la mise à jour des données. La fonction .nextTick fournie par Vue a émergé pour résoudre ce type de problème. Cet article présentera en détail l'utilisation de la fonction Vue.nextTick et la combinera avec des exemples de code pour illustrer son application dans les mises à jour asynchrones. 1. Vue.nex

PHP-FPM est un gestionnaire de processus PHP couramment utilisé pour offrir de meilleures performances et stabilité PHP. Cependant, dans un environnement à forte charge, la configuration par défaut de PHP-FPM peut ne pas répondre aux besoins, nous devons donc l'ajuster. Cet article présentera en détail la méthode de réglage de PHP-FPM et donnera quelques exemples de code. 1. Augmentez le nombre de processus Par défaut, PHP-FPM ne démarre qu'un petit nombre de processus pour gérer les requêtes. Dans un environnement à charge élevée, nous pouvons augmenter la concurrence de PHP-FPM en augmentant le nombre de processus.

L'opérateur modulo (%) en PHP est utilisé pour obtenir le reste de la division de deux nombres. Dans cet article, nous discuterons en détail du rôle et de l'utilisation de l'opérateur modulo et fournirons des exemples de code spécifiques pour aider les lecteurs à mieux comprendre. 1. Le rôle de l'opérateur modulo En mathématiques, lorsqu'on divise un entier par un autre entier, on obtient un quotient et un reste. Par exemple, lorsque l’on divise 10 par 3, le quotient est 3 et le reste est 1. L'opérateur modulo est utilisé pour obtenir ce reste. 2. Utilisation de l'opérateur modulo En PHP, utilisez le symbole % pour représenter le module

Explication détaillée de la fonction d'appel système Linux system() L'appel système est une partie très importante du système d'exploitation Linux. Il fournit un moyen d'interagir avec le noyau système. Parmi elles, la fonction system() est l’une des fonctions d’appel système couramment utilisées. Cet article présentera en détail l’utilisation de la fonction system() et fournira des exemples de code correspondants. Concepts de base des appels système Les appels système sont un moyen permettant aux programmes utilisateur d'interagir avec le noyau du système d'exploitation. Les programmes utilisateur demandent au système d'exploitation en appelant des fonctions d'appel système
