Vous savez peut-être que l'environnement d'exécution du langage Javascript est "single thread".
Le soi-disant « fil unique » signifie qu'une seule tâche peut être accomplie à la fois. S'il y a plusieurs tâches, elles doivent être mises en file d'attente. Une fois la tâche précédente terminée, la tâche suivante sera exécutée, et ainsi de suite.
L'avantage de ce mode est qu'il est relativement simple à mettre en œuvre et l'environnement d'exécution est relativement simple ; l'inconvénient est que tant qu'une tâche prend beaucoup de temps, les tâches suivantes doivent être mises en file d'attente, ce qui retarder l'exécution de l'ensemble du programme. L'absence de réponse courante du navigateur (mort suspendue) est souvent causée par un certain morceau de code Javascript exécuté pendant une longue période (comme une boucle infinie), ce qui bloque la page entière à cet endroit et empêche d'autres tâches d'être effectuées.
Afin de résoudre ce problème, le langage Javascript divise le mode d'exécution des tâches en deux types : synchrone (Synchronous) et asynchrone (Asynchronous).
Le « Mode synchrone » est le mode du paragraphe précédent. Cette dernière tâche attend la fin de la tâche précédente avant de l'exécuter. L'ordre d'exécution du programme est cohérent et synchrone avec l'ordre des tâches ; mode" est complètement différent. Chaque tâche a une ou plusieurs fonctions de rappel. Une fois la tâche précédente terminée, la fonction de rappel est exécutée à la place de la tâche suivante. Cette dernière tâche est exécutée avant la fin de la tâche précédente, donc l'ordre d'exécution du programme est incohérent et asynchrone avec l’ordre des tâches.
Le "mode asynchrone" est très important. Du côté du navigateur, les opérations de longue durée doivent être effectuées de manière asynchrone pour éviter que le navigateur ne réponde. Le meilleur exemple est celui des opérations Ajax. Du côté du serveur, le « mode asynchrone » est même le seul mode, car l'environnement d'exécution est monothread. Si toutes les requêtes http peuvent être exécutées de manière synchrone, les performances du serveur chuteront fortement et il perdra bientôt sa réponse.
Cet article résume 4 méthodes de programmation en "mode asynchrone". Les comprendre vous permettra d'écrire des programmes Javascript avec une structure plus raisonnable, de meilleures performances et une maintenance plus facile.
1. Fonction de rappel
Il s'agit de la méthode la plus basique de programmation asynchrone.
Supposons qu'il y ait deux fonctions f1 et f2, et que cette dernière attend le résultat de l'exécution de la première.
f1();f2();
Si f1 est une tâche fastidieuse, vous pouvez envisager de réécrire f1 et d'écrire f2 comme fonction de rappel de f1.
function f1(callback){ setTimeout(function () { // f1的任务代码 callback(); }, 1000); }
Le code d'exécution devient le suivant :
f1(f2);
De cette façon, nous transformons l'opération synchrone en une opération asynchrone, et f1 ne bloquera pas le programme en cours d'exécution, ce qui est équivalent à Exécuter d'abord la logique principale du programme et reporter l'exécution des opérations chronophages.
L'avantage de la fonction de rappel est qu'elle est simple, facile à comprendre et à déployer. L'inconvénient est qu'elle n'est pas propice à la lecture et à la maintenance du code. Les différentes parties sont fortement couplées (Couplage). Le processus sera déroutant et chaque tâche ne peut être spécifiée qu'une fonction de rappel.
2. Surveillance des événements
Une autre façon de penser est d'utiliser le modèle événementiel. L'exécution d'une tâche ne dépend pas de l'ordre du code, mais de la survenance d'un événement.
Prenons f1 et f2 comme exemple. Tout d’abord, liez un événement à f1 (jQuery est utilisé ici).
f1.on('done', f2);
La ligne de code ci-dessus signifie que lorsque l'événement done se produit dans f1, f2 sera exécuté. Ensuite, réécrivez f1 :
function f1(){ setTimeout(function () { // f1的任务代码 f1.trigger('done'); }, 1000); }
f1.trigger('done') signifie qu'une fois l'exécution terminée, l'événement done sera déclenché immédiatement pour commencer l'exécution de f2.
L'avantage de cette méthode est qu'elle est relativement facile à comprendre, qu'elle peut lier plusieurs événements, que chaque événement peut spécifier plusieurs fonctions de rappel et qu'elle peut être « découplée », ce qui est propice à la modularisation. L'inconvénient est que l'ensemble du programme doit être piloté par des événements et que le processus en cours devient très flou.
3. Publier/Abonnez-vous
L'« événement » de la section précédente peut être compris comme un « signal ».
Nous supposons qu'il existe un "centre de signal". Lorsqu'une tâche est terminée, elle "publie" un signal au centre de signal. D'autres tâches peuvent "s'abonner" au signal du centre de signal. sachez quand vous pouvez commencer à exécuter. C'est ce qu'on appelle le « modèle de publication-abonnement », également connu sous le nom de « modèle d'observateur ».
Il existe de nombreuses implémentations de ce modèle. Celle utilisée ci-dessous est Tiny Pub/Sub de Ben Alman, qui est un plug-in pour jQuery.
Tout d'abord, f2 s'abonne au signal "terminé" du jQuery "Signal Center".
jQuery.subscribe("done", f2);
Ensuite, f1 est réécrit comme suit :
function f1(){ setTimeout(function () { // f1的任务代码 jQuery.publish("done"); }, 1000); }
jQuery.publish("done") signifie qu'après l'exécution de f1, envoyez un message au " signal center" jQuery libère le signal "done", déclenchant ainsi l'exécution de f2.
De plus, une fois l'exécution de f2 terminée, vous pouvez également vous désinscrire.
jQuery.unsubscribe("done", f2);
La nature de cette méthode est similaire à "l'écoute d'événements", mais elle est évidemment meilleure que cette dernière. Parce que nous pouvons surveiller le fonctionnement du programme en consultant le « Centre de messages » pour voir combien de signaux existent et combien d'abonnés possède chaque signal.
4. Objet Promises
L'objet Promises est une spécification proposée par le groupe de travail CommonJS pour fournir une interface unifiée pour la programmation asynchrone.
En termes simples, l'idée est que chaque tâche asynchrone renvoie un objet Promise, qui possède une méthode then qui permet de spécifier une fonction de rappel. Par exemple, la fonction de rappel f2 de f1 peut s'écrire :
f1().then(f2);
f1要进行如下改写(这里使用的是jQuery的实现):
function f1(){ var dfd = $.Deferred(); setTimeout(function () { // f1的任务代码 dfd.resolve(); }, 500); return dfd.promise; }
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
比如,指定多个回调函数:
f1().then(f2).then(f3);
再比如,指定发生错误时的回调函数:
f1().then(f2).fail(f3);
而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
你可能知道,Javascript语言的执行环境是”单线程”(single thread)。
所谓”单线程”,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。
这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。
为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
“同步模式”就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;”异步模式”则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
“异步模式”非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,”异步模式”甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
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!