Vous savez peut-être que l'environnement d'exécution du langage Javascript est "单线程
" (un seul 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, retarderont 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 (rappel). Une fois la tâche précédente terminée, au lieu d'exécuter la tâche suivante, elle exécute la fonction de rappel. Cette dernière tâche n'attend pas le précédent. Les tâches sont exécutées lorsqu'elles sont terminées, 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.
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 (Coupling
). , le processus sera très déroutant et chaque tâche n'a besoin que d'une fonction de rappel pouvant être spécifiée.
Une autre façon de penser consiste à utiliser le modèle basé sur les événements. 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 (la méthode d'écriture de jQuery est utilisée 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, commençant ainsi à exécuter f2.
L'avantage de cette méthode est qu'elle est relativement simple à comprendre, elle peut lier plusieurs événements, chaque événement peut spécifier plusieurs fonctions de rappel, et elle peut être "découplée", ce qui est bénéfique pour la mise en œuvre du module Changement . 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.
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 » (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")
的意思是,f1执行完成后,向”信号中心”jQuery发布”done”信号,从而引发f2的执行。
此外,f2完成执行后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
Promises
对象是CommonJS
工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise
对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:
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);
而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
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!